home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-06-04 | 392.4 KB | 12,683 lines |
- ;
- ; EJEMPLOS DEL LENGUAJE C
- ;
-
- ; LECCION 1
- begin
- begine " OPERACIONES ARITMETICAS "
- /*
- El siguiente programa calcula la suma, diferencia, producto, cociente y
- resto de dos números enteros.
- Una vez calculado estos valores los imprime y espera a que el usuario
- pulsa la tecla RETURN para finalizar.
- */
-
- #include <stdio.h> /* para utilizar: printf (), getchar () */
-
- void main (void)
- {
- int numero1, numero2;
- int suma, diferencia, producto, cociente, resto;
-
- numero1 = 10;
- numero2 = 3;
- suma = numero1 + numero2;
- diferencia = numero1 - numero2;
- producto = numero1 * numero2;
- cociente = numero1 / numero2;
- resto = numero1 % numero2;
-
- printf ("OPERACIONES ARITMETICAS SOBRE DOS NUMEROS ENTEROS:");
- printf ("\n\nNúmero 1: %d", numero1);
- printf ("\nNúmero 2: %d", numero2);
- printf ("\n\nSuma: %d", suma);
- printf ("\nDiferencia: %d", diferencia);
- printf ("\nProducto: %d", producto);
- printf ("\nCociente: %d", cociente);
- printf ("\nResto: %d", resto);
-
- printf ("\n\nPulsa la tecla RETURN para terminar programa.");
- getchar ();
- }
- ende
- begine " PASOS EN EL DESARROLLO DE UN PROGRAMA "
- /*
- Este programa escribe un esquema en pantalla.
- */
-
- #include <stdio.h> /* para poder utilizar las funciones printf() y getchar() */
-
- void main (void)
- {
- printf (" FASES EN EL DESARROLLO DE UN PROGRAMA\n");
- printf (" \n");
- printf (" ┌───────────┐ \n");
- printf (" │ EDICION │ \n");
- printf (" └───────────┘ \n");
- printf (" │ \n");
- printf (" programa fuente \n");
- printf (" │ \n");
- printf (" ┌───────────┐ \n");
- printf (" │COMPILACION│ \n");
- printf (" └───────────┘ \n");
- printf (" │ \n");
- printf (" programa objeto \n");
- printf (" │ \n");
- printf (" ┌───────────┐ \n");
- printf (" │ ENLAZADO │ \n");
- printf (" └───────────┘ \n");
- printf (" │ \n");
- printf (" programa ejecutable \n");
- printf (" │ \n");
- printf (" ┌───────────┐ \n");
- printf (" │ EJECUCION │ \n");
- printf (" └───────────┘ \n");
- getchar ();
- }
- ende
- end
-
- ; LECCION 2
- begin
- begine " CALCULO DE LA LONGITUD Y EL AREA DE UN CIRCULO "
- /*
- El siguiente programa calcula la longitud y el área de un círculo de radio 2.5
- */
-
- #include <stdio.h> // printf (), getchar ()
-
- void main (void)
- {
- const float pi = 3.141592;
- float radio, longitud, area;
-
- radio = 2.5;
- longitud = 2 * pi * radio;
- area = pi * radio * radio;
-
- printf ("Cálculo de la longitud y área de un círculo de radio %f:\n\n", radio);
- printf ("\tLONGITUD: %f\n", longitud);
- printf ("\tAREA : %f\n", area);
-
- printf ("\nPulsa la tecla RETURN para salir.\n");
- getchar ();
- }
- ende
- begine " TAMAÑO DE LOS TIPOS MAS USADOS EN C "
- /*
- Este programa muestra el tamaño de los tipos más usados en C en el
- sistema en el cual se ejecuta el programa.
- */
-
- #include <stdio.h> /* printf(), getchar() */
-
- void main (void)
- {
- printf ("TAMAÑO DE ALGUNOS TIPOS EN EL SISTEMA EN QUE SE EJECUTA EL PROGRAMA:\n\n");
- printf (" Tipo Tamaño (en bytes)\n");
- printf (" ------------ -----------------\n");
- printf (" char %d \n", sizeof (char));
- printf (" int %d \n", sizeof (int));
- printf (" short int %d \n", sizeof (short int));
- printf (" long int %d \n", sizeof (long int));
- printf (" float %d \n", sizeof (float));
- printf (" double %d \n", sizeof (double));
- printf (" long double %d \n", sizeof (long double));
- printf ("\nPulsa la tecla RETURN para salir.\n");
- getchar ();
- }
- ende
- end
-
- ; LECCION 3
- begin
- begine " ORDENACION POR EL METODO DE INSERCION DIRECTA "
- /*
- En este programa se realiza la ordenación creciente de un vector de números
- enteros.
-
- El método de ordenación seguido ha sido el de inserción directa (denominado
- también método de la baraja).
-
- Supongamos un vector v de n componentes. El método consiste en repetir el
- siguiente proceso desde la segunda componente hasta la última: Se toma
- dicha componente y se inserta en el lugar que le corresponda entre las
- componentes situadas a su izquierda (éstas ya estarán ordenadas). Las
- componentes superiores a la tratada se desplazarán un lugar a la derecha.
-
- Ejemplo:
-
- Secuencia inicial 7 5 1 2 4
- Primer paso 5 7 1 2 4
- Segundo paso 1 5 7 2 4
- Tercer paso 1 2 5 7 4
- Cuarto paso 1 2 4 5 7
-
- En este programa aparece una función que no se ha visto en teoría: rand ().
- Esta función devuelve un valor aleatorio entre 0 y RAND_MAX. Tanto la función
- rand () como la constante RAND_MAX están declaradas en la librería stdlib.h.
- El valor de RAND_MAX suele ser el valor del mayor número int con signo.
- */
-
- #include <stdio.h> /* printf (), getchar () */
- #include <stdlib.h> /* rand () */
-
- void main (void)
- {
- int vector [100]; /* declaración de un vector de 100 elementos int */
- int i, j, aux; /* declaración de tres variables int: dos de índice y una auxiliar */
-
- /* Escritura de la cabecera. */
- printf ("ORDENACION DE UN VECTOR DESORDENADO POR EL METODO DE INSERCION DIRECTA:");
-
- /* Relleno aleatorio de los 100 componentes del vector. A cada componente se
- le asigna un valor aleatorio entre 0 y 999. Las componentes del vector van
- desde la 0 hasta la 99 inclusive. */
- for (i = 0; i <= 99; i++)
- vector[i] = rand () % 1000;
-
- /* Escritura en pantalla del vector desordenado. */
- printf ("\n Vector desordenado:\n");
- for (i = 0; i < 100; i++)
- printf ("%d\t", vector[i]);
-
- /* Ordenación del vector por el método de inserción directa. */
- for (i = 1; i <= 99; i++)
- {
- aux = vector[i];
- for (j = i - 1; vector[j] > aux && j > 0; j--)
- vector[j+1] = vector[j];
- if (vector[j] > aux)
- {
- vector[j+1] = vector[j];
- vector[j] = aux;
- }
- else
- vector[j+1] = aux;
- }
-
- /* Escritura en pantalla del vector ordenado. */
- printf ("\n Vector ordenado:\n");
- for (i = 0; i < 100; i++)
- printf ("%d\t", vector[i]);
-
- /* Espera la pulsación de la tecla RETURN para finalizar el programa. */
- getchar ();
- }
- ende
- begine " ORDENACION POR EL METODO DE SELECCION DIRECTA "
- /*
- En este programa se realiza la ordenación creciente de un vector de números
- enteros.
-
- El método de ordenación seguido ha sido el de selección directa.
-
- Supongamos un vector v de n componentes. El método consiste en repetir el
- siguiente proceso desde el primer elemento hasta el penúltimo: Se selecciona
- la componente de menor valor de todas las situadas a la derecha de la tratada
- y se intercambia con ésta.
-
- Ejemplo:
-
- Secuencia inicial 7 5 1 2 4
- Primer paso 1 5 7 2 4
- Segundo paso 1 2 7 5 4
- Tercer paso 1 2 4 5 7
- Cuarto paso 1 2 4 5 7
-
- En este programa aparece una función que no se ha visto en teoría: rand ().
- Esta función devuelve un valor aleatorio entre 0 y RAND_MAX. Tanto la función
- rand () como la constante RAND_MAX están declaradas en la librería stdlib.h.
- El valor de RAND_MAX suele ser el valor del mayor número int con signo.
- */
-
- #include <stdio.h> /* printf (), getchar () */
- #include <stdlib.h> /* rand () */
-
- void main (void)
- {
- int vector [100]; /* declaración de un vector de 100 elementos int */
- int i, j, k, aux; /* declaración de cuatro variables int: tres de índice y una auxiliar */
-
- /* Escritura de la cabecera. */
- printf ("ORDENACION DE UN VECTOR DESORDENADO POR EL METODO DE SELECCION DIRECTA:");
-
- /* Relleno aleatorio de los 100 componentes del vector. A cada componente se
- le asigna un valor aleatorio entre 0 y 999. Las componentes del vector van
- desde la 0 hasta la 99 inclusive. */
- for (i = 0; i <= 99; i++)
- vector[i] = rand () % 1000;
-
- /* Escritura en pantalla del vector desordenado. */
- printf ("\n Vector desordenado:\n");
- for (i = 0; i < 100; i++)
- printf ("%d\t", vector[i]);
-
- /* Ordenación del vector por el método de selección directa. */
- for (i = 0; i <= 98; i++)
- {
- k = i;
- aux = vector[i];
- for (j = i + 1; j <= 99; j++)
- if (vector[j] < aux)
- {
- k = j;
- aux = vector[j];
- }
- vector[k] = vector[i];
- vector[i] = aux;
- }
-
- /* Escritura en pantalla del vector ordenado. */
- printf ("\n Vector ordenado:\n");
- for (i = 0; i < 100; i++)
- printf ("%d\t", vector[i]);
-
- /* Espera la pulsación de la tecla RETURN para finalizar el programa. */
- getchar ();
- }
- ende
- begine " ORDENACION POR EL METODO DE LA BURBUJA "
- /*
- En este programa se realiza la ordenación creciente de un vector de números
- enteros.
-
- El método de ordenación seguido ha sido el de la burbuja. Es un método de
- intercambio directo.
-
- Este método tiene dos versiones basadas en la misma idea que consiste en
- recorrer sucesivamente el vector comparando los elementos consecutivos e
- intercambiándolos cuando estén descolocados. El recorrido del vector se
- puede hacer de izquierda a derecha (desplazando los valores mayores hacia
- su derecha) o de derecha a izquierda (desplazando los valores menores
- hacia su izquierda), ambos para la clasificación en orden ascendente.
-
- Recorrido izquierda-derecha: Esta versión del método va colocando en cada
- pasada el mayor elemento de los tratados en la última posición quedando
- colocado y por lo tanto excluido de los elementos a tratar en la siguiente
- pasada.
-
- Ejemplo:
-
- Secuencia inicial 7 5 1 2 4
- Primer paso 5 1 2 4 7
- Segundo paso 1 2 4 5 7
- Tercer paso 1 2 4 5 7
- Cuarto paso 1 2 4 5 7
-
- Recorrido derecha-izquierda: Esta versión es simétrica a la anterior
- desplazando los elementos menores hacia la izquiera.
-
- Ejemplo:
-
- Secuencia inicial 7 5 1 2 4
- Primer paso 1 7 5 2 4
- Segundo paso 1 2 7 5 4
- Tercer paso 1 2 4 7 5
- Cuarto paso 1 2 4 5 7
-
- En este programa aparece una función que no se ha visto en teoría: rand ().
- Esta función devuelve un valor aleatorio entre 0 y RAND_MAX. Tanto la función
- rand () como la constante RAND_MAX están declaradas en la librería stdlib.h.
- El valor de RAND_MAX suele ser el valor del mayor número int con signo.
- */
-
- #include <stdio.h> /* printf (), getchar () */
- #include <stdlib.h> /* rand () */
-
- void main (void)
- {
- int vector [100]; /* declaración de un vector de 100 elementos int */
- int i, j, aux; /* declaración de tres variables int: dos de índice y una auxiliar */
-
- /* Escritura de la cabecera. */
- printf ("ORDENACION DE UN VECTOR DESORDENADO POR EL METODO DE LA BURBUJA:");
-
- /* Relleno aleatorio de los 100 componentes del vector. A cada componente se
- le asigna un valor aleatorio entre 0 y 999. Las componentes del vector van
- desde la 0 hasta la 99 inclusive. */
- for (i = 0; i <= 99; i++)
- vector[i] = rand () % 1000;
-
- /* Escritura en pantalla del vector desordenado. */
- printf ("\n Vector desordenado:\n");
- for (i = 0; i < 100; i++)
- printf ("%d\t", vector[i]);
-
- /* Ordenación del vector por el método de intercambio directo (de la burbuja)
- con recorrido de izquierda a derecha. */
- for (i = 98; i >= 0; i--)
- for (j = 0; j <= i; j++)
- if (vector[j] > vector[j+1])
- {
- aux = vector[j];
- vector[j] = vector[j+1];
- vector[j+1] = aux;
- }
-
- /* Ordenación del vector por el método de intercambio directo (de la burbuja)
- con recorrido de derecha a izquierda. */
- for (i = 1; i <= 99; i++)
- for (j = 99; j >= i; j--)
- if (vector[j-1] > vector[j])
- {
- aux = vector[j-1];
- vector[j-1] = vector[j];
- vector[j] = aux;
- }
-
- /* Escritura en pantalla del vector ordenado. */
- printf ("\n Vector ordenado:\n");
- for (i = 0; i < 100; i++)
- printf ("%d\t", vector[i]);
-
- /* Espera la pulsación de la tecla RETURN para finalizar el programa. */
- getchar ();
- }
- ende
- begine " ORDENACION POR EL METODO DE LA SACUDIDA "
- /*
- En este programa se realiza la ordenación creciente de un vector de números
- enteros.
-
- El método de ordenación seguido ha sido el de la sacudida. Es un método de
- intercambio directo.
-
- Consiste en mezclar las dos versiones del método de la burbuja alternativamente,
- de tal forma que se realiza una pasada de derecha a izquierda y a continuación
- otra de izquierda a derecha, recortándose los elementos a tratar por ambos lados
- del vector.
-
- Este método es más eficiente que el de la burbuja en la mayoría de los casos.
-
- Ejemplo:
-
- Secuencia inicial 7 5 1 2 4
- Primer paso 1 7 5 2 4
- Segundo paso 1 5 2 4 7
- Tercer paso 1 2 5 4 7
- Cuarto paso 1 2 4 5 7
-
- En este programa aparece una función que no se ha visto en teoría: rand ().
- Esta función devuelve un valor aleatorio entre 0 y RAND_MAX. Tanto la función
- rand () como la constante RAND_MAX están declaradas en la librería stdlib.h.
- El valor de RAND_MAX suele ser el valor del mayor número int con signo.
- */
-
- #include <stdio.h> /* printf (), getchar () */
- #include <stdlib.h> /* rand () */
-
- void main (void)
- {
- int vector [100]; /* declaración de un vector de 100 elementos int */
- int i, j, izq, der, aux; /* declaración de cinco variables int */
-
- /* Escritura de la cabecera. */
- printf ("ORDENACION DE UN VECTOR DESORDENADO POR EL METODO DE LA SACUDIDA:");
-
- /* Relleno aleatorio de los 100 componentes del vector. A cada componente se
- le asigna un valor aleatorio entre 0 y 999. Las componentes del vector van
- desde la 0 hasta la 99 inclusive. */
- for (i = 0; i <= 99; i++)
- vector[i] = rand () % 1000;
-
- /* Escritura en pantalla del vector desordenado. */
- printf ("\n Vector desordenado:\n");
- for (i = 0; i < 100; i++)
- printf ("%d\t", vector[i]);
-
- /* Ordenación del vector por el método de selección directa. */
- izq = 1;
- der = 99;
- do
- {
- for (j = der; j >= izq; j--)
- if (vector[j-1] > vector[j])
- {
- aux = vector[j-1];
- vector[j-1] = vector[j];
- vector[j] = aux;
- }
- izq++;
- for (j = izq; j <= der; j++)
- if (vector[j-1] > vector[j])
- {
- aux = vector[j-1];
- vector[j-1] = vector[j];
- vector[j] = aux;
- }
- der--;
- } while (izq <= der);
-
- /* Escritura en pantalla del vector ordenado. */
- printf ("\n Vector ordenado:\n");
- for (i = 0; i < 100; i++)
- printf ("%d\t", vector[i]);
-
- /* Espera la pulsación de la tecla RETURN para finalizar el programa. */
- getchar ();
- }
- ende
- begine "ORDENACION POR EL METODO DE INTERCAMBIO DIRECTO CON TEST DE COMPROBACION"
- /*
- En este programa se realiza la ordenación creciente de un vector de números
- enteros.
-
- El método de ordenación seguido ha sido el de intercambio directo con test
- de comprobacion.
-
- Es una mejora de los métodos de intercambio directo en la que se comprueba
- mediante un interruptor si el vector está totalmente ordenado después de
- cada pasada, terminando la ejecución en caso afirmativo.
-
- En este programa aparece una función que no se ha visto en teoría: rand ().
- Esta función devuelve un valor aleatorio entre 0 y RAND_MAX. Tanto la función
- rand () como la constante RAND_MAX están declaradas en la librería stdlib.h.
- El valor de RAND_MAX suele ser el valor del mayor número int con signo.
- */
-
- #include <stdio.h> /* printf (), getchar () */
- #include <stdlib.h> /* rand () */
-
- void main (void)
- {
- int vector [100]; /* declaración de un vector de 100 elementos int */
- int i, j, interruptor, aux; /* declaración de cuatro variables int */
-
- /* Escritura de la cabecera. */
- printf ("ORDENACION POR EL METODO DE INTERCAMBIO CON TEST DE COMPROBACION:");
-
- /* Relleno aleatorio de los 100 componentes del vector. A cada componente se
- le asigna un valor aleatorio entre 0 y 999. Las componentes del vector van
- desde la 0 hasta la 99 inclusive. */
- for (i = 0; i <= 99; i++)
- vector[i] = rand () % 1000;
-
- /* Escritura en pantalla del vector desordenado. */
- printf ("\n Vector desordenado:\n");
- for (i = 0; i < 100; i++)
- printf ("%d\t", vector[i]);
-
- /* Ordenación del vector por el método de intercambio directo con test de
- comprobación. */
- i = 0;
- do
- {
- i++;
- interruptor = 0;
- for (j = 99; j >= i; j--)
- if (vector[j-1] > vector[j])
- {
- aux = vector[j-1];
- vector[j-1] = vector[j];
- vector[j] = aux;
- interruptor = 1;
- }
- } while (interruptor == 1 && i <= 99);
-
- /* Escritura en pantalla del vector ordenado. */
- printf ("\n Vector ordenado:\n");
- for (i = 0; i < 100; i++)
- printf ("%d\t", vector[i]);
-
- /* Espera la pulsación de la tecla RETURN para finalizar el programa. */
- getchar ();
- }
- ende
- begine " ORDENACION POR EL METODO SHELL "
- /*
- En este programa se realiza la ordenación creciente de un vector de números
- enteros.
-
- El método de ordenación seguido ha sido el de inserción con incrementos
- decrecientes (también denominado método shell).
-
- Es una mejora del método de inserción directa en la cual se produce un
- acercamiento de los elementos descolocados hacia su posición correcta en
- saltos de mayor longitud. Se repite un mismo proceso con una distancia de
- comparación que inicialmente es la mitad de la longitud del vector y que
- se va reduciendo a la mitad en cada repetición hasta que dicha distancia
- vale 1. Cada pasada termina al detectarse mediante un interruptor la
- ordenación a la distancia correspondiente.
-
- Ejemplo:
-
- Secuencia inicial
- 7 5 1 2 4 9 0 3 1
-
- Primer paso. Distancia de comparación 4.
- 7 5 1 2 4 9 0 3 1
- └───────────────┘ │ │ │ │
- └───────────────┘ │ │ │
- └───────────────┘ │ │
- └───────────────┘ │
- └───────────────┘
- 4 5 0 2 1 9 1 3 7
- └───────────────┘ │ │ │ │
- └───────────────┘ │ │ │
- └───────────────┘ │ │
- └───────────────┘ │
- └───────────────┘
- 1 5 0 2 4 9 1 3 7 ordenados los pares de distancia 4
-
- Segundo paso. Distancia de comparación 2.
- 1 5 0 2 4 9 1 3 7
- └───────┘ │ │ │ │ │ │
- └───────┘ │ │ │ │ │
- └───────┘ │ │ │ │
- └───────┘ │ │ │
- └───────┘ │ │
- └───────┘ │
- └───────┘
- 0 2 1 5 1 3 4 9 7
- └───────┘ │ │ │ │ │ │
- └───────┘ │ │ │ │ │
- └───────┘ │ │ │ │
- └───────┘ │ │ │
- └───────┘ │ │
- └───────┘ │
- └───────┘
- 0 2 1 3 1 5 4 9 7 ordenados los pares de distancia 2
-
- Tercer paso. Distancia de comparación 1.
- 0 2 1 3 1 5 4 9 7
- └───┘ │ │ │ │ │ │ │
- └───┘ │ │ │ │ │ │
- └───┘ │ │ │ │ │
- └───┘ │ │ │ │
- └───┘ │ │ │
- └───┘ │ │
- └───┘ │
- └───┘
- 0 1 2 1 3 4 5 7 9
- └───┘ │ │ │ │ │ │ │
- └───┘ │ │ │ │ │ │
- └───┘ │ │ │ │ │
- └───┘ │ │ │ │
- └───┘ │ │ │
- └───┘ │ │
- └───┘ │
- └───┘
- 0 1 1 2 3 4 5 7 9 ordenados los pares de distancia 1
-
- En este programa aparece una función que no se ha visto en teoría: rand ().
- Esta función devuelve un valor aleatorio entre 0 y RAND_MAX. Tanto la función
- rand () como la constante RAND_MAX están declaradas en la librería stdlib.h.
- El valor de RAND_MAX suele ser el valor del mayor número int con signo.
- */
-
- #include <stdio.h> /* printf (), getchar () */
- #include <stdlib.h> /* rand () */
-
- void main (void)
- {
- int vector [100]; /* declaración de un vector de 100 elementos int */
- int i, division, interruptor, aux; /* declaración de cuatro variables int */
-
- /* Escritura de la cabecera. */
- printf ("ORDENACION POR EL METODO SHELL:");
-
- /* Relleno aleatorio de los 100 componentes del vector. A cada componente se
- le asigna un valor aleatorio entre 0 y 999. Las componentes del vector van
- desde la 0 hasta la 99 inclusive. */
- for (i = 0; i <= 99; i++)
- vector[i] = rand () % 1000;
-
- /* Escritura en pantalla del vector desordenado. */
- printf ("\n Vector desordenado:\n");
- for (i = 0; i < 100; i++)
- printf ("%d\t", vector[i]);
-
- /* Ordenación del vector por el método shell. */
- division = 99;
- do
- {
- division /= 2;
- do
- {
- interruptor = 0;
- i = 0;
- do
- {
- if (vector[i] > vector[i+division])
- {
- aux = vector[i];
- vector[i] = vector[i+division];
- vector[i+division] = aux;
- interruptor = 1;
- }
- } while (i++ + division < 99);
- } while (interruptor == 1);
- } while (division > 1);
-
- /* Escritura en pantalla del vector ordenado. */
- printf ("\n Vector ordenado:\n");
- for (i = 0; i < 100; i++)
- printf ("%d\t", vector[i]);
-
- /* Espera la pulsación de la tecla RETURN para finalizar el programa. */
- getchar ();
- }
- ende
- begine " BUSQUEDA LINEAL EN VECTOR DESORDENADO "
- /*
- En este programa se realiza una búsqueda lineal en un vector desordenado de
- números enteros.
-
- Método seguido: Se recorre el vector de izquierda a derecha hasta encontrar
- una componente cuyo valor coincida con el buscado o hasta que se acabe el
- vector. En este último caso, el algoritmo debe indicar la no existencia de
- dicho valor. En los casos en que pueda aparecer el valor repetido, el
- algoritmo indicará el de índice menor. Con una pequeña modificación podemos
- obtener las distintas posiciones que ocupa el valor.
-
- Este método es válido tanto para vectores desordenados como ordenados, aunque
- para vectores ordenados veremos otros métodos más eficientes en los ejemplos
- siguientes.
- */
-
- #include <stdio.h> /* printf (), getchar () */
- #include <stdlib.h> /* rand () */
-
- void main (void)
- {
- int vector [100]; /* declaración de un vector de 100 elementos int */
- int i, x; /* declaración de dos variables int: i se utiliza como índice
- para recorrer el vector y x contendrá el valor a buscar en
- el vector */
-
- /* Escritura de la cabecera. */
- printf ("BUSQUEDA LINEAL EN UN VECTOR DESORDENADO:");
-
- /* Relleno aleatorio de los 100 componentes del vector. A cada componente se
- le asigna un valor aleatorio entre 0 y 999. Las componentes del vector van
- desde la 0 hasta la 99 inclusive. También se asigna un valor aleatorio a
- la variable x que contiene el valor a buscar. */
- for (i = 0; i <= 99; i++)
- vector[i] = rand () % 1000;
- x = rand () % 1000;
-
- /* Escritura en pantalla del vector desordenado y valor a buscar. */
- printf ("\n\nVector:\n");
- for (i = 0; i < 100; i++)
- printf ("%d\t", vector[i]);
- printf ("\nValor a buscar: %d", x);
-
- /* Búsqueda lineal en vector desordenado. */
- for (i = 0; i <= 99 && vector[i] != x; i++)
- ;
-
- /* Escritura en pantalla del vector ordenado. */
- if (i <= 99)
- printf ("\n\nValor %d encontrado en índice %d (recordar que empieza en 0).", x, i);
- else
- printf ("\n\nNo existe el valor %d en el vector.", x);
- /* Espera la pulsación de la tecla RETURN para finalizar el programa. */
- getchar ();
- }
- ende
- begine " BUSQUEDA LINEAL EN VECTOR ORDENADO "
- /*
- En este programa se realiza una búsqueda lineal en un vector ordenado de
- números enteros.
-
- Cuando el vector de búsqueda está ordenado se consigue un algoritmo más
- eficiente que el del ejemplo anterior sin más que modificar la codificación
- de terminación en el algoritmo del ejemplo anterior.
-
- La ventana que se obtiene es en el caso de orden ascendente, una vez
- sobrepasado el valor buscado, no es necesario recorrer el resto del vector
- para saber que el valor no existe.
- */
-
- #include <stdio.h> /* printf (), getchar () */
-
- void main (void)
- {
- int vector [100]; /* declaración de un vector de 100 elementos int */
- int i, x; /* declaración de dos variables int: i se utiliza como índice
- para recorrer el vector y x contendrá el valor a buscar en
- el vector */
-
- /* Escritura de la cabecera. */
- printf ("BUSQUEDA LINEAL EN UN VECTOR ORDENADO:");
-
- /* Relleno aleatorio de los 100 componentes del vector. A cada componente se
- le asigna un valor equivalente al doble del índice que ocupan en el vector.
- A la variable x se le asigna arbitrariamente la mitad de lo que vale la
- variable i al salir del bucle. */
- for (i = 0; i <= 99; i++)
- vector[i] = i * 2;
- x = i / 2;
-
- /* Escritura en pantalla del vector ordenado y valor a buscar. */
- printf ("\n\nVector:\n");
- for (i = 0; i < 100; i++)
- printf ("%d\t", vector[i]);
- printf ("\nValor a buscar: %d", x);
-
- /* Búsqueda lineal en vector ordenado. */
- for (i = 0; i <= 99 && vector[i] < x; i++)
- ;
-
- /* Escritura en pantalla del vector ordenado. */
- if (i <= 99)
- printf ("\n\nValor %d encontrado en índice %d (recordar que empieza en 0).", x, i);
- else
- printf ("\n\nNo existe el valor %d en el vector.", x);
- /* Espera la pulsación de la tecla RETURN para finalizar el programa. */
- getchar ();
- }
- ende
- begine " BUSQUEDA BINARIA "
- /*
- En este programa se realiza una búsqueda binaria (llamada también dicotómica)
- en un vector ordenado de números enteros.
-
- Este algoritmo es válido exclusivamente para vectores ordenados y consiste
- en comparar en primer lugar con la componente central del vector, y si no
- es igual al valor buscado se reduce el intervalo de búsqueda a la mitad
- derecha o izquierda según donde pueda encontrarse el valor a buscar. El
- algoritmo termina si se encuentra el valor buscado o si el tamaño del
- intervalo de búsqueda queda anulado.
-
- En los casos en que existan repeticiones en el vector, del valor buscado,
- este algoritmo obtendrá uno de ellos aleatoriamente según los lugares que
- ocupen, los cuales necesariamente son consecutivos.
- */
-
- #include <stdio.h> /* printf (), getchar () */
-
- void main (void)
- {
- int vector [100]; /* declaración de un vector de 100 elementos int */
- int x, /* contiene valor a buscar */
- encontrado, /* variable que sólo toma dos valores: cierto (1) o falso (0) */
- i, centro, izquierda, derecha; /* índices de vector */
-
- /* Escritura de la cabecera. */
- printf ("BUSQUEDA BINARIA EN UN VECTOR ORDENADO:");
-
- /* Relleno aleatorio de los 100 componentes del vector. A cada componente se
- le asigna un valor equivalente al doble del índice que ocupan en el vector.
- A la variable x se le asigna arbitrariamente la mitad de lo que vale la
- variable i al salir del bucle. */
- for (i = 0; i <= 99; i++)
- vector[i] = i * 2;
- x = i / 2;
-
- /* Escritura en pantalla del vector ordenado y valor a buscar. */
- printf ("\n\nVector:\n");
- for (i = 0; i < 100; i++)
- printf ("%d\t", vector[i]);
- printf ("\nValor a buscar: %d", x);
-
- /* Búsqueda binaria en vector ordenado. */
- encontrado = 0;
- izquierda = 0;
- derecha = 99;
- while (! encontrado && izquierda <= derecha)
- {
- centro = (izquierda + derecha) / 2;
- if (x < vector[centro])
- derecha = centro - 1;
- else if (x > vector[centro])
- izquierda = centro + 1;
- else
- encontrado = 1;
- }
-
- /* Escritura en pantalla del vector ordenado. */
- if (encontrado)
- printf ("\n\nValor %d encontrado en índice %d (recordar que empieza en 0).", x, centro);
- else
- printf ("\n\nNo existe el valor %d en el vector.", x);
- /* Espera la pulsación de la tecla RETURN para finalizar el programa. */
- getchar ();
- }
- ende
- begint
- begine " GENERACION DE 0 Y 1 ALEATORIAMENTE "
- /*
- En ejemplos anteriores hemos dicho que la función rand () devuelve un
- número aleatorio entre 0 y RAND_MAX; tanto la función rand () como la
- constante RAND_MAX están definidos en la librería stdlib.h.
-
- Si has ejecutado alguno de los ejemplos anteriores en los que se generan
- números aleatorios, habrás observado que siempre se genera la misma se-
- cuencia de números aleatorios. Esto se debe a que cada número aleatorio
- se genera a partir del anterior; y como el primer número, llamado semilla,
- siempre es el mismo, siempre obtenemos la misma secuencia de números.
-
- En la librería stdlib.h del C estándar tenemos la función srand (). Esta
- función inicializa el generador de números aleatorios con una semilla. Esta
- semilla es un número entero que debemos pasar como parámetro a la función
- srand(). La función srand() no devuelve ningún valor. Por ejemplo: srand (3);
-
- Turbo C dispone de dos funciones más utilizadas que rand () y srand ().
- Dichas funciones son: random () y randomize (); ambas funciones se encuentran
- en stdlib.h.
-
- La función randomize () no acepta ningún parámetro ni devuelve nada. Inicia-
- liza el generador de números aleatorios con un valor aleatorio. Para obtener
- este valor inicial utiliza una función de tiempo que se encuentra en la li-
- brería time.h. Por lo tanto, siempre que utilicemos la función randomize,
- hemos de incluir los ficheros stdlib.h y time.h. Consejo: cuando en un pro-
- grama generemos números aleatorios debemos realizar una llamada a la función
- randomize antes de generar el primero. Ejemplo de llamada: randomize ();
-
- La función random acepta un número n como argumento y devuelve un número
- aleatorio entre 0 y (n-1). Por ejemplo, la instrucción: x = ramdom (10);
- asigna a la variable x un número aleatorio entre 0 y 9.
-
- Con lo que acabamos de hablar hemos completado todo lo que hay en el C con
- respecto a números aleatorios.
-
- El código fuente que hay continuación es un ejemplo de todo lo que hemos
- hablado sobre números aleatorios.
- */
-
- #include <time.h> /* randomize () */
- #include <stdlib.h> /* randomize (), random () */
- #include <stdio.h> /* printf (), getchar () */
-
- void main (void)
- {
- const int numero_de_valores_a_generar = 80 * 24, valor_maximo = 2;
- int i;
-
- randomize ();
- for (i = 1; i <= numero_de_valores_a_generar; i++)
- printf ("%d", random (valor_maximo));
- getchar ();
- }
- ende
- endt
- end
-
- ; LECCION 4
- begin
- begine " TRANSFORMACION DE NOTA NUMERICA A ALFABETICA "
- /*
- Este programa lee una calificación entre 0 y 10 y la transforma en nota
- alfabética según la siguiente tabla:
-
- Nota numérica Nota alfabética
- -------------------------------
- 0 <= NOTA < 3 MUY DEFICIENTE
- 3 <= NOTA < 5 INSUFICIENTE
- 5 <= NOTA < 6 SUFICIENTE
- 7 <= NOTA < 9 NOTABLE
- 9 <= NOTA <= 10 SOBRESALIENTE
- Imprimiendo el resultado.
- */
-
- #include <stdio.h> // printf (), scanf (), getchar ()
-
- void main (void)
- {
- int nota;
-
- printf ("Introduce una calificación (0-10): ");
- scanf ("%d", ¬a);
-
- printf ("\nLa notación numérica %d equivale a la alfabética ", nota);
- switch (nota)
- {
- case 0:
- case 1:
- case 2:
- printf ("MUY DEFICIENTE.");
- break;
- case 3:
- case 4:
- printf ("INSUFICIENTE.");
- break;
- case 5:
- printf ("SUFICIENTE.");
- break;
- case 6:
- printf ("BIEN.");
- break;
- case 7:
- case 8:
- printf ("NOTABLE.");
- break;
- case 9:
- case 10:
- printf ("SOBRESALIENTE.");
- break;
- default:
- printf ("NOTA INCORRECTA.");
- }
-
- printf ("\n\nPulsa la tecla RETURN para finalizar.");
- getchar (); /* esta función recoge el RETURN que no coge el scanf () */
- getchar (); /* esta función espera a que el usuario pulse RETURN */
- }
- ende
- begine "CONTADOR DE NUMEROS POSITS, NEGATS Y NULOS DE UNA SERIE"
- /*
- Este programa lee una secuencia de números y obtiene e imprime cuántos hay
- positivos, negativos y nulos.
- */
-
- #include <stdio.h> // printf (), scanf ()
- #include <conio.h> // getch ()
-
- void main (void)
- {
- int n, i, valor, num_de_valores_posit, num_de_valores_negat;
-
- printf ("\nIntroduce el número de valores a leer: ");
- scanf ("%d", &n);
- printf ("\nIntroduce los %d valores: ", n);
-
- for (num_de_valores_posit = num_de_valores_negat = 0, i = 1; i <= n; i++)
- {
- scanf ("%d", &valor);
- if (valor > 0)
- ++num_de_valores_posit;
- else if (valor < 0)
- ++num_de_valores_negat;
- }
-
- printf ("\nNúmero de valores positivos introducidos: %d.",
- num_de_valores_posit);
- printf ("\nNúmero de valores negativos introducidos: %d.",
- num_de_valores_negat);
- printf ("\nNúmero de valores nulos introducidos: %d.",
- n - (num_de_valores_posit + num_de_valores_negat));
-
- printf ("\n\nPulsa cualquier tecla para finalizar.");
- getch ();
- }
- ende
- begine " CALCULO DEL MAYOR Y MENOR NUMERO DE UNA SERIE "
- /*
- Este programa lee una secuencia de números terminados con la introducción
- de un 0, y obtiene e imprime el mayor y el menor de ellos.
- */
-
- #include <stdio.h> // printf (), scanf ()
- #include <conio.h> // getch ()
-
- void main (void)
- {
- int valor, valor_mayor, valor_menor;
- printf ("\nIntroduce una serie de valores terminados en 0: ");
- scanf ("%d", &valor);
- if (valor == 0)
- printf ("\nNo se ha introducido ningún valor.");
- else
- {
- valor_mayor = valor_menor = valor;
- while (valor != 0)
- {
- if (valor > valor_mayor)
- valor_mayor = valor;
- if (valor < valor_menor)
- valor_menor = valor;
- scanf ("%d", &valor);
- }
- printf ("\nMayor valor introducido: %d.\nMenor valor introducido: %d.",
- valor_mayor, valor_menor);
- }
- printf ("\n\nPulsa cualquier tecla para finalizar.");
- getch ();
- }
- ende
- begine " INVERSION DE UN VECTOR "
- /*
- El siguiente programa lee 10 números y los escribe en orden inverso.
- */
-
- #include <stdio.h> // printf (), scanf ()
- #include <conio.h> // getch ()
-
- void main (void)
- {
- const numero_de_valores_a_leer = 10;
- int numeros [numero_de_valores_a_leer];
- int i;
-
- printf ("\nIntroduce %d números: ", numero_de_valores_a_leer);
- for (i = 0; i <= numero_de_valores_a_leer - 1; i++)
- scanf ("%d", &numeros[i]);
-
- printf ("\nNúmeros leídos en orden inverso:");
- for (i = numero_de_valores_a_leer - 1; i >= 0; i--)
- printf (" %d", numeros[i]);
-
- printf ("\n\nPulsa cualquier tecla para finalizar.");
- getch ();
- }
- ende
- begine " CALCULO DE LA MEDIA DE UNA SERIE DE NUMEROS "
- /*
- Este programa lee por el teclado las notas de los alumnos de una clase y
- calcula el número de ellas y su media. Para terminar la introducción de
- notas se introduce una nota negativa.
- */
-
- #include <stdio.h> // printf (), scanf ()
- #include <conio.h> // getch ()
-
- void main (void)
- {
- int nota, numero_de_notas, suma_de_las_notas;
-
- printf ("\nPara terminar de introducir notas, escribir nota negativa.\n\n");
- printf ("Introduce nota 1: ");
- scanf ("%d", ¬a);
- numero_de_notas = suma_de_las_notas = 0;
- while (nota >= 0)
- {
- numero_de_notas++;
- suma_de_las_notas += nota;
- printf ("Introduce nota %d: ", numero_de_notas + 1);
- scanf ("%d", ¬a);
- }
- if (numero_de_notas == 0)
- printf ("\n\nNo se ha introducido ninguna nota.");
- else
- printf ("\n\nMedia de las notas introducidas: %g",
- (float) suma_de_las_notas / numero_de_notas);
- printf ("\n\n\nPulsa cualquier tecla para finalizar.");
- getch ();
- }
- ende
- begine " VISUALIZADOR DE MEMORIA "
- /*
- Este programa visualiza 256 bytes de memoria a partir de la dirección
- de comienzo especificada.
- */
-
- #include <stdio.h> /* printf (), scanf () */
- #include <conio.h> /* getch () */
-
- void main (void)
- {
- register int i;
- unsigned char ch, *p;
-
- printf ("VISUALIZAR MEMORIA.\n\n");
-
- printf ("Dirección de comienzo (en hex): ");
- scanf ("%p%*c", &p);
-
- printf ("\n%p: ", p); /* imprime dirección */
- for (i = 1; i <= 256; i++)
- {
- ch = *p;
- printf ("%02x ", ch); /* visualiza en hexadecimal */
- p++;
- if (! (i % 16)) /* cada 16 bytes salta a la línea siguiente */
- {
- printf ("\n");
- if (i != 256)
- printf ("%p: ", p); /* imprime dirección */
- }
- }
-
- getch ();
- }
- ende
- end
-
- ; LECCION 5
- begin
- begine " TORRES DE HANOI "
- /*
- Este programa mueve n discos de una columna a otra columna utilizando una
- columna auxiliar. Cada disco es de un tamaño distinto y nunca se puede
- poner un disco mayor sobre un disco menor. Sólo se puede mover un disco
- cada vez.
-
- Veamos cómo se resolvería en el caso de tres discos:
-
- Situación inicial:
-
- │ │ │
- ▄▄│▄▄ │ │
- ▄▄▄│▄▄▄ │ │
- ▄▄▄▄│▄▄▄▄ │ │
- ─────┴───── ─────┴───── ─────┴─────
- columna a columna b columna c
-
- Movimiento 1:
-
- │ │ │
- │ │ │
- ▄▄▄│▄▄▄ │ │
- ▄▄▄▄│▄▄▄▄ │ ▄▄│▄▄
- ─────┴───── ─────┴───── ─────┴─────
- columna a columna b columna c
-
- Movimiento 2:
-
- │ │ │
- │ │ │
- │ │ │
- ▄▄▄▄│▄▄▄▄ ▄▄▄│▄▄▄ ▄▄│▄▄
- ─────┴───── ─────┴───── ─────┴─────
- columna a columna b columna c
-
- Movimiento 3:
-
- │ │ │
- │ │ │
- │ ▄▄│▄▄ │
- ▄▄▄▄│▄▄▄▄ ▄▄▄│▄▄▄ │
- ─────┴───── ─────┴───── ─────┴─────
- columna a columna b columna c
-
- Movimiento 4:
-
- │ │ │
- │ │ │
- │ ▄▄│▄▄ │
- │ ▄▄▄│▄▄▄ ▄▄▄▄│▄▄▄▄
- ─────┴───── ─────┴───── ─────┴─────
- columna a columna b columna c
-
- Movimiento 5:
-
- │ │ │
- │ │ │
- │ │ │
- ▄▄│▄▄ ▄▄▄│▄▄▄ ▄▄▄▄│▄▄▄▄
- ─────┴───── ─────┴───── ─────┴─────
- columna a columna b columna c
-
- Movimiento 6:
-
- │ │ │
- │ │ │
- │ │ ▄▄▄│▄▄▄
- ▄▄│▄▄ │ ▄▄▄▄│▄▄▄▄
- ─────┴───── ─────┴───── ─────┴─────
- columna a columna b columna c
-
- Movimiento 7:
-
- │ │ │
- │ │ ▄▄│▄▄
- │ │ ▄▄▄│▄▄▄
- │ │ ▄▄▄▄│▄▄▄▄
- ─────┴───── ─────┴───── ─────┴─────
- columna a columna b columna c
-
- Las columnas las designamos por letras y los movimientos serán del tipo:
- a --> b
-
- Si el número de discos es mayor que 0:
- Mover n discos de 'a' a 'c' usando 'b' es equivalente a:
- mover n-1 discos de 'a' a 'b' usando c
- mover 1 disco de 'a' a 'c'
- mover n-1 discos de 'b' a 'c' usando a
-
- En este programa conviene utilizar la recursividad a la iteratividad ya
- que la lógica es mucho más fácil.
- */
-
- /* Ficheros a incluir: */
-
- #include <stdio.h> /* printf (), puts (), putchar (), scanf () */
- #include <conio.h> /* getch () */
- #include <stdlib.h> /* exit () */
-
- /* Declaración de funciones: */
-
- void mover_varios_discos (int n, char p, char q, char r);
- void mover_un_disco (char f, char g);
-
- /* Definición de funciones: */
-
- void main (void)
- {
- int numero_de_discos;
-
- puts ("TORRES DE HANOI");
- printf ("\nIntroduce número de discos a mover: ");
- scanf ("%d", &numero_de_discos);
- putchar ('\n');
-
- mover_varios_discos (numero_de_discos, 'a', 'c', 'b');
-
- printf ("\nPulsa cualquier tecla para finalizar.");
- getch ();
- }
-
- void mover_varios_discos (int numero_de_discos, char columna_origen,
- char columna_destino, char columna_auxiliar)
- {
- if (numero_de_discos > 0)
- {
- mover_varios_discos (numero_de_discos-1, columna_origen, columna_auxiliar,
- columna_destino);
- mover_un_disco (columna_origen, columna_destino);
- mover_varios_discos (numero_de_discos-1, columna_auxiliar, columna_destino,
- columna_origen);
- }
- }
-
- void mover_un_disco (char columna_origen, char columna_destino)
- {
- static unsigned int numero_de_movimiento = 0;
- /* cada 24 movimientos se para la escritura */
- if (++numero_de_movimiento % 24 == 0)
- {
- printf ("Pulsa la tecla ESCAPE para salir o cualquier otra tecla para continuar.");
- /* el código ASCII 27 corresponde a la tecla ESCAPE */
- if (getch () == 27)
- exit (0);
- /* con estas tres funciones se borra el mensaje anterior */
- putchar ('\r');
- printf (" ");
- putchar ('\r');
- }
- printf ("Movimiento %2u: %c --> %c\n", numero_de_movimiento, columna_origen,
- columna_destino);
- }
- ende
- begine " PERMUTACIONES "
- /*
- Este programa lee los elementos de un vector y escribe todas las
- permutaciones (combinaciones sin repetición) posibles de los
- elementos introducidos en el vector.
-
- El número de permutaciones de n elementos está determinado por el
- factorial de n.
-
- Observaciones sobre el programa:
-
- 1) En el primer elemento del vector (índice 0) se encuentra el
- número de elementos a permutar. Así pues, los n elementos a
- permutar están en entre los índices 1 y n el vector.
-
- 2) En algunos sitios del programa aparece la expresión:
- &vector[i]
- que puede parecer a simple un poco rara para el que no está
- acostumbrado al C. Expliquémosla: Al ser cada elmento del
- vector de tipo int, vector[i] se puede considerar como una
- variable de tipo int, y por lo tanto, podemos hacer con la
- expresión vector[i] lo que con cualquier variable de tipo
- entero, y no de estas operaciones es obtener su dirección.
- Hemos dicho varias veces que el nombre del vector es un puntero
- al primer elemento, así la siguiente expresión sería cierta:
- vector == &vector[0], es decir, que vector y &vector[0] es
- equivalente.
-
- 3) Los nombres de las variables punteros, por convención, suelen
- empezar con p; por este motivo he llamado a los parámetros de la
- función intercambiar p1 y p2.
- */
-
- /* Ficheros a incluir: */
-
- #include <stdio.h> /* printf (), puts (), putchar (), scanf () */
- #include <conio.h> /* getch () */
- #include <stdlib.h> /* exit () */
-
- /* Macros: */
-
- #define NUMERO_MAXIMO_ELEMENTOS_VECTOR 100
- #define en(x,x1,x2) ((x) >= (x1) && (x) <= (x2))
-
- /* Declaración de las funciones: */
-
- void rellenar_vector (int vect[]);
- void escribir_vector (int vect[]);
- void permutar (int v[], int m);
- void intercambiar (int *p1, int *p2);
-
- /* Definición de las funciones: */
-
- void main (void)
- {
- int vector [NUMERO_MAXIMO_ELEMENTOS_VECTOR+1]; /* +1 porque el primer
- elemento contiene el número de elementos a permutar */
-
- puts ("PERMUTACIONES");
- rellenar_vector (vector);
-
- permutar (vector, vector[0]);
-
- printf ("\nPulsa cualquier tecla para finalizar.");
- getch ();
- }
-
- void rellenar_vector (int vect[])
- {
- register int i;
- do
- {
- printf ("\nIntroduce número de elementos de vector (1-%d): ",
- NUMERO_MAXIMO_ELEMENTOS_VECTOR);
- scanf ("%d", &vect[0]);
- } while (! en (vect[0], 1, NUMERO_MAXIMO_ELEMENTOS_VECTOR));
- printf ("\nIntroduce los %d elementos a permutar: ", vect[0]);
- for (i = 1; i <= vect[0]; i++)
- scanf ("%d", &vect[i]);
- putchar ('\n');
- }
-
- void escribir_vector (int vect[])
- {
- static unsigned int numero_de_permutacion = 0;
- register int i;
-
- /* cada 24 movimientos se para la escritura */
- if (++numero_de_permutacion % 24 == 0)
- {
- printf ("Pulsa la tecla ESCAPE para salir o cualquier otra tecla para continuar.");
- /* el código ASCII 27 corresponde a la tecla ESCAPE */
- if (getch () == 27)
- exit (0);
- /* con estas tres funciones se borra el mensaje anterior */
- putchar ('\r');
- printf (" ");
- putchar ('\r');
- }
- printf ("Permutación %2u: ", numero_de_permutacion);
- for (i = 1; i <= vect[0]; i++)
- printf ("%d ", vect[i]);
- putchar ('\n');
- }
-
- void permutar (int v[], int m)
- {
- register int i;
- if (m > 1)
- for (i = 1; i <= m; i++)
- {
- intercambiar (&v[i], &v[m]);
- permutar (v, m-1);
- intercambiar (&v[i], &v[m]);
- }
- else
- escribir_vector (v);
- }
-
- void intercambiar (int *p1, int *p2)
- {
- int aux;
- aux = *p1;
- *p1 = *p2;
- *p2 = aux;
- }
- ende
- begine " ORDENACION POR EL METODO DE ORDENACION RAPIDA "
- /*
- En este programa se realiza la ordenación creciente de un vector de números
- enteros.
-
- El método de ordenación seguido ha sido el de ordenación rápida.
-
- La ordenación rápida, inventada y nombrada por C.A.R. Hoare, es mejor que
- todas las vistas en los ejemplos de la lección 4 y está generalmente con-
- siderada como el mejor algoritmo de ordenación disponible actualmente. Está
- basada en la ordenación por el método de intercambio.
-
- La ordenación rápida se basa en la idea de las particiones. El procedimiento
- general es seleccionar un valor llamado comparando y entonces dividir el
- array en dos partes. En un lado todos los elementos mayores o iguales al
- valor de partición y en otro todos los elementos menores que el valor. Este
- proceso se repite en cada parte restante hasta que el array está ordenado.
-
- Como se puede ver, este proceso es esencialmente recursivo por naturaleza y,
- de hecho, las implementaciones más claras de la ordenación rápida es por al-
- goritmos recursivos.
-
- La selección del valor comparado se puede obtener de dos formas. Se puede
- seleccionar aleatoriamente o haciendo la media de un pequeño conjunto de
- valores tomados del array. Para una ordenación óptima es mejor seleccionar
- un valor que esté precisamente en medio del rango de valores. Sin embargo,
- esto no es fácil de hacer en la mayoría de los conjuntos de datos. En el
- caso peor, el valor escogido está en un extremo. Incluso en este, la orde-
- nación rápida todavía funciona bien. La versión de la ordenación rápida que
- sigue selecciona el elemento mitad del array. Aunque no siempre será una
- buena elección, la ordenación sigue funcionanado correctamente.
-
- Ejemplo:
-
- Secuencia inicial 8 2 5 3 9
- Elemento comparando: 5
- Primer paso 3 2 5 8 9
- Ahora se ordena con el mismo procedimiento los vectores '3 2' y '8 9'
-
- En este programa aparece una función que no se ha visto en teoría: rand ().
- Esta función devuelve un valor aleatorio entre 0 y RAND_MAX. Tanto la función
- rand () como la constante RAND_MAX están declaradas en la librería stdlib.h.
- El valor de RAND_MAX suele ser el valor del mayor número int con signo. Esta
- función ya se vio en los ejemplos de la lección 4.
- */
-
- #include <stdio.h> /* printf () */
- #include <stdlib.h> /* rand () */
- #include <conio.h> /* getch () */
-
- #define NUM_ELEMENTOS_VECTOR 100
-
- void ordenar (int vect[], int ind_izq, int ind_der);
-
- void main (void)
- {
- int vector [NUM_ELEMENTOS_VECTOR]; /* declaración de un vector de elementos int */
- register int i; /* declaración de una variable resistro de tipo entera */
-
- /* Escritura de la cabecera. */
- printf ("ORDENACION DE UN VECTOR DESORDENADO POR EL METODO DE ORDENACION RAPIDA:");
-
- /* Relleno aleatorio de los 100 componentes del vector. A cada componente se
- le asigna un valor aleatorio entre 0 y 999. Las componentes del vector van
- desde la 0 hasta la NUM_ELEMENTOS_VECTOR-1 inclusive. */
- for (i = 0; i < NUM_ELEMENTOS_VECTOR; i++)
- vector[i] = rand () % 1000;
-
- /* Escritura en pantalla del vector desordenado. */
- printf ("\n Vector desordenado:\n");
- for (i = 0; i < NUM_ELEMENTOS_VECTOR; i++)
- printf ("%d\t", vector[i]);
-
- /* Ordenación del vector por el método de inserción directa. */
- ordenar (vector, 0, NUM_ELEMENTOS_VECTOR-1);
-
- /* Escritura en pantalla del vector ordenado. */
- printf ("\n Vector ordenado:\n");
- for (i = 0; i < NUM_ELEMENTOS_VECTOR; i++)
- printf ("%d\t", vector[i]);
-
- /* Espera la pulsación de cualquier tecla para finalizar el programa. */
- getch ();
- }
-
- void ordenar (int vect[], int ind_izq, int ind_der)
- { /* vect: vector, ind_izq: índice izquierdo, ind_der: índice derecho */
- register int i, j; /* variables índice del vector */
- int elem; /* contiene un elemento del vector */
-
- i = ind_izq;
- j = ind_der;
- elem = vect[(ind_izq+ind_der)/2];
-
- do
- {
- while (vect[i] < elem && j < ind_der) /* recorrido del vector hacia la derecha */
- i++;
- while (elem < vect[j] && j > ind_izq) /* recorrido del vector hacia la izquierda */
- j--;
- if (i <= j) /* intercambiar */
- {
- int aux; /* variable auxiliar */
- aux = vect[i];
- vect[i] = vect[j];
- vect[j] = aux;
- i++;
- j--;
- }
- } while (i <= j);
- if (ind_izq < j)
- ordenar (vect, ind_izq, j);
- if (i < ind_der)
- ordenar (vect, i, ind_der);
- }
- ende
- begint
- begine " DIBUJO DE UN GRAFICO "
- /*
- Este programa dibuja un gráfico de una forma recursiva. Está implementado
- en Turbo C.
-
- Ejecutar el programa antes de leer la explicación sobre el mismo para
- enteder la explicación mejor.
-
- La atractiva forma gráfica que muestra en la ejecución del programa está
- formada por la superposición de cinco curvas. Estas siguen un esquema
- regular y sugieren que deben poder dibujarse por un «plotter» controlado
- por computador. El objetivo a conseguir es descubrir el esquema recursivo
- con el que debe construirse el programa que haga el dibujo. Por inspección
- se observa que tres de las curvas superpuestas tienen la forma indicada
- en los dibujos siguientes; se designan por H1, H2 y H3.
-
- Curva de Hilbert de orden 1:
-
- ┌───────
- │
- │
- └───────
-
- Curva de Hilbert de orden 2:
-
- ┌───────┐
- │ │ │
- └───┐ └───┘
- │
- ┌───┘ ┌───┐
- │ │ │
- └───────┘
-
- Curva de Hilbert de orden 3:
-
- ┌───┐ ┌───┐ ┌─
- └─┐ └─┘ ┌─┘ └─┐
- ┌─┘ ┌─┐ │ ┌─┐ │
- └───┘ │ └─┘ └─┘
- ┌───┐ │ ┌─┐ ┌─┐
- └─┐ └─┘ │ └─┘ │
- ┌─┘ ┌─┐ └─┐ ┌─┘
- └───┘ └───┘ └─
-
- Las figuras muestran que H(i+1) se obtiene por composición de cuatro curvas
- de tipo H(i) de tamaño mitad, giradas apropiadamente, y unidas por tres
- líneas. Obsérvese que H(1) puede considerarse formada por cuatro curvas de
- un tipo vacío H(0) conectadas por tres rectas. H(i) se denomina curva de
- Hilbert de orden i, en honor a su inventor D. Hilbert (1891).
-
- Supóngase que las herramientas básicas de que se dispone para dibujar son
- dos variables de coordenadas x e y, un procedimiento setplot (situar la
- pluma del «plotter» en las coordenadas x e y) y un procedimiento plot (que
- mueve la pluma de dibujo desde la situación actual a la posición indicada
- por x e y).
-
- Como cada curva H(i) está formada por cuatro copias de tamaño mitad de la
- curva H(i-1) es lógico expresar el procedimiento de dibujar H(i) como
- compuesto de cuatro partes, cada una dibujando una H(i-1) del tamaño apro-
- piado, convenientemente girada. Si se denomina cada parte, respectivamente,
- por A, B, C y D, y las rutinas que dibujan las correspondientes líneas de
- interconexión se representan por flechas apuntando en la dirección corres-
- pondiente aparece el siguiente esquema recursivo:
-
- ┌─
- └─> A: D <- A A -> B
-
- ┌─┐
- │ B: C B -> B A
-
- <─┐
- ─┘ C: B -> C C <- D
-
- │
- └─┘ D: A D <- D C
-
- Si se designa la línea unitaria por h, el procedimiento correspondiente al
- esquema A se expresa inmediatamente uilizando activaciones recursivas de los
- procedimientos designados análogamente por B y D y del propio A.
-
- procedimiento A (i es entero)
- si i > 0 entonces
- D (i-1); x = x - h; plot;
- A (i-1); y = y - h; plot;
- A (i-1); x = x + h; plot;
- B (i-1);
- finsi
- finprocedimiento
-
- Este procedimiento se inicia por el programa principal una vez por cada curva
- de Hilbert a superponer. El programa principal determina el punto inicial de
- la curva, o sea, los valores iniciales de x e y, y el incremento unitario h. Se
- llama h0 al ancho total de la página, que debe ser h0 = (2 elevado a k) para
- algún k ≥ n. El programa completo dibuja las n curvas de Hilbert H1, ... Hn.
-
- Descripción de las características gráficas utilizadas de Turbo C (concreta-
- mente de la versión Borland C++ 2.0).
-
- Para trabajar con gráfico es necesario incluir el fichero <graphics.h>.
-
- En Turbo C, siempre que se vaya a utilizar el modo gráfico, es necesario
- inicializarlo y cerrarlo.
-
- La inicialización se hace con la función initgraph(). El prototipo de esta
- función es:
-
- void initgraph (int *graphdriver, int *graphmode, char *pathtodriver);
-
- donde graphdriver debe contener el dispositivo gráfico; los valores que
- puede tomar son:
-
- CGA MCGA
- EGA EGA64
- EGAMONO IBM8514
- HERCMONO ATT400
- VGA PC3270
- DETECT (autodetección de la tarjeta gráfica)
-
- En graphmode se guarda el modo gráfico para cada dispositivo gráfico; los
- valores que puede tomar son:
-
- ════════════╤═════════════╤══════════════
- CGAC0 │ 320 x 200 │ paleta 0
- CGAC1 │ 320 x 200 │ paleta 1
- CGAC2 │ 320 x 200 │ paleta 2
- CGAC3 │ 320 x 200 │ paleta 3
- CGAHI │ 640 x 200 │ 2 colores
- │ │
- MCGAC0 │ 320 x 200 │ paleta 0
- MCGAC1 │ 320 x 200 │ paleta 1
- MCGAC2 │ 320 x 200 │ paleta 2
- MCGAC3 │ 320 x 200 │ paleta 3
- MCGAMED │ 640 x 200 │ 2 colores
- MCGAHI │ 640 x 480 │ 2 colores
- │ │
- EGALO │ 640 x 200 │ 16 colores
- EGAHI │ 640 x 350 │ 16 colores
- EGA64LO │ 640 x 200 │ 16 colores
- EGA64HI │ 640 x 350 │ 4 colores
- │ │
- EGAMONOHI │ 640 x 350 │ 2 colores
- HERCMONOHI │ 720 x 348 │ 2 colores
- │ │
- ATT400C0 │ 320 x 200 │ paleta 0
- ATT400C1 │ 320 x 200 │ paleta 1
- ATT400C2 │ 320 x 200 │ paleta 2
- ATT400C3 │ 320 x 200 │ paleta 3
- ATT400MED │ 640 x 200 │ 2 colores
- ATT400HI │ 640 x 400 │ 2 colores
- │ │
- VGALO │ 640 x 200 │ 16 colores
- VGAMED │ 640 x 350 │ 16 colores
- VGAHI │ 640 x 480 │ 16 colores
- │ │
- PC3270HI │ 720 x 350 │ 2 colores
- IBM8514LO │ 640 x 480 │256 colores
- IBM8514HI │ 1024 x 768 │256 colores
-
- En pathtodriver debe estar el path del directorio donde están los ficheros
- con extensión .BGI. Su sintaxis es:
-
- "..\\bgi\\drivers"
-
- El modo gráfico se cierra con la función closegraph() cuyo prototipo es:
-
- void closegraph (void);
-
- La esquina izquierda superior de la pantalla gráfica tiene coordenadas: 0, 0.
-
- Funciones gráficas utilizadas en este programa:
-
- 1) void lineto (int x, int y);
-
- Dibuja una línea desde la posición actual del cursor gráfico hasta (x,y).
-
- 2) void moveto (int x, int y);
-
- Mueve el cursor gráfico a (x,y).
-
- 3) int graphresult (void);
-
- Devuelve un código de error para la última operación gráfica no exitosa
- o grOk si la última operación gráfica ha tenido éxito.
-
- Los códigos de error devueltos por graphresult() son:
-
- grOk grNoInitGraph
- grNotDetected grFileNotFound
- grInvalidDriver grNoLoadMem
- grNoScanMem grNoFloodMem
- grFontNotFound grNoFontMem
- grInvalidMode grError
- grIOerror grInvalidFont
- grInvalidFontNum grInvalidDeviceNum
- grInvalidVersion
-
- 4) char *grapherrormsg (int errorcode);
-
- Devuelve un puntero a un string con el mensaje de error.
-
- 5) void setviewport (int izq, int ar, int der, int ab, int clip);
-
- Crea un viewport para la salida gráfica.
- Un viewport es una ventana de trabajo en la pantalla gráfica de tal
- modo que la coordenada (0,0) corresponde a la esquina izquierda superior
- del viewport y no de la pantalla.
- El parámetro clip especifica si los valores fuera del viewport son
- recortados.
-
- Las características gráficas de Turbo C se estudiará en lecciones posteriores.
- Aquí sólo hemos dado los conceptos básicos sobre ellas para comprender cómo
- está hecho el programa.
- */
-
- #include <graphics.h> /* lineto (), moveto (), setviewport (), initgrah (),
- graphresult (), grOk, getmaxx (), getmaxy () */
- #include <stdio.h> /* printf () */
- #include <conio.h> /* geth () */
- #include <stdlib.h> /* exit (), EXIT_FAILURE */
-
- int h0, h, x, y;
-
- void a (int), b (int), c (int), d (int);
- void inicializar_grafico (void);
-
- #define empezargraf inicializar_grafico ();
- #define plot lineto (x, y)
- #define setplot moveto (x, y);
- #define terminargraf closegraph ();
-
- void main (void)
- {
- const int n = 4;
- int i, x0, y0;
-
- empezargraf;
-
- i = 0;
- h = h0;
- x0 = h / 2;
- y0 = x0;
-
- do
- {
- i++;
- h /= 2;
- x0 += (h/2);
- y0 += (h/2);
- x = x0;
- y = y0;
- setplot;
- a (i);
- } while (i != n);
-
- getch ();
- terminargraf;
- }
-
- void inicializar_grafico (void)
- {
- int gdriver = DETECT, gmode;
- int vpx1, vpy1, vpx2, vpy2;
- int errorcode;
-
- initgraph (&gdriver, &gmode, "");
- errorcode = graphresult ();
-
- if (errorcode != grOk)
- {
- printf ("Error Gráfico: %s\n", grapherrormsg (errorcode));
- getch ();
- exit (EXIT_FAILURE);
- }
-
- h0 = getmaxx () + 1 >= 640 && getmaxy () + 1 >= 480 ? 512 : 128;
-
- /* calcula las coordenadas de viewport para crear un viewport en el centro
- de la pantalla de altura y anchura h0 si puede; esto se hace para que
- el gráfico salga centrado en la pantalla */
- vpx1 = (getmaxx () + 1 - h0) / 2 + 1;
- vpy1 = getmaxy () + 1 <= h0 ? 0 : (getmaxy () + 1 - h0) / 2 + 1;
- vpx2 = vpx1 + h0 - 1;
- vpy2 = getmaxy () + 1 <= h0 ? getmaxy () : vpy1 + h0 - 1;
-
- setviewport (vpx1, vpy1, vpx2, vpy2, 0);
- }
-
- void a (int i)
- {
- if (i > 0)
- {
- d (i-1); x -= h; plot;
- a (i-1); y -= h; plot;
- a (i-1); x += h; plot;
- b (i-1);
- }
- }
-
- void b (int i)
- {
- if (i > 0)
- {
- c (i-1); y += h; plot;
- b (i-1); x += h; plot;
- b (i-1); y -= h; plot;
- a (i-1);
- }
- }
-
- void c (int i)
- {
- if (i > 0)
- {
- b (i-1); x += h; plot;
- c (i-1); y += h; plot;
- c (i-1); x -= h; plot;
- d (i-1);
- }
- }
-
- void d (int i)
- {
- if (i > 0)
- {
- a (i-1); y -= h; plot;
- d (i-1); x -= h; plot;
- d (i-1); y += h; plot;
- c (i-1);
- }
- }
- ende
- begine " DIBUJO DE UN GRAFICO 2 "
- /*
- Este programa dibuja un gráfico de una forma recursiva. Está implementado
- en Turbo C.
-
- Ejecutar el programa antes de leer la explicación sobre el mismo para
- enteder la explicación mejor. Leer además también la explicación del
- ejemplo anterior antes que ésta.
-
- Este ejemplo es semejante al anterior aunque algo más complejo y más
- sofisticado desde el punto de vista estético. Esta forma se obtiene
- también por superposición de varias curvas. S(i) se denomina la curva
- de Sierpinski de orden i. ¿Cuál es el esquema recursivo? Se siente uno
- tentado de identificar la «hoja» S(1) como bloque básico de construcción,
- posiblemente quitándole un borde. Pero esto no conduce a una solución. La
- diferencia principal entre las curvas de Hilbert y Sierpinski es que estas
- últimas son cerradas (sin discontinuidades). Esto implica que el esquema
- básico de recursión debe ser una curva abierta y que las cuatro partes
- deben estar conectadas por líneas no pertenecientes al propio esquema
- recursivo. Realmente, estas líneas están formadas por cuatro rectas en
- las cuatro esquinas de los bordes. Pueden considerarse como pertenecientes
- a una curva inicial no vacía, S(0), que es un cuadrado apoyado en un vértice.
-
- A partir de esto, el esquema recursivo se establece inmediatamente. Las
- formas básicas se denominan nuevamente A, B, C y D y las líneas de conexión
- se dibujan explícitamente. Obsérvese que los cuatro esquemas recursivos son
- idénticos realmente, con la única diferencia de que están girados 90º.
-
- S: A diagonal_hacia_abajo_de_izq_a_der
- B diagonal_hacia_abajo_de_der_a_izq
- C diagonal_hacia_arriba_de_der_a_izq
- D diagonal_hacia_arriba_de_izq_a_der
-
- y los esquemas recursivos son
-
- A: A diagonal_hacia_abajo_de_izq_a_der
- B linea_horizontal_doble_de_izq_a_der
- D diagonal_hacia_arriba_de_izq_a_der
- A
-
- B: B diagonal_hacia_abajo_de_der_a_izq
- C linea_horizontal_doble_de_ar_a_ab
- A diagonal_hacia_abajo_de_izq_a_der
- B
-
- C: C diagonal_hacia_arriba_de_der_a_izq
- D linea_horizontal_doble_de_der_a_izq
- B diagonal_hacia_abajo_de_der_a_izq
- C
-
- D: D diagonal_hacia_arriba_de_izq_a_der
- A linea_horizontal_doble_de_ab_a_ar
- C diagonal_hacia_arriba_de_der_a_izq
- D
-
- Si se usan los mismos procedimientos básicos para la operaciones de dibujo
- que en el ejemplo de las curvas de Hilbert, el anterior esquema recursivo
- se transforma sin dificultad en un algoritmo (directa e indirectamente)
- recursivo.
-
- procedimiento A (i es estero)
- si i > 0 entonces
- A (i-1); x = x + h; y = y - h; plot;
- B (i-1); x = x + 2 * h; plot;
- D (i-1); x = x + h; y = y + h; plot;
- A (i-1);
- finsi
- finprocedimiento
-
- Pueden obtenerse en forma análoga procedimientos correspondientes a los
- esquemas B, C y D.
-
- Las características gráficas utilizadas en este programa están explicadas
- en el ejemplo anterior ya que los dos ejemplos son similares.
- */
-
- #include <graphics.h> /* lineto (), moveto (), setviewport (), initgrah (),
- graphresult (), grOk, getmaxx (), getmaxy () */
- #include <stdio.h> /* printf () */
- #include <conio.h> /* geth () */
- #include <stdlib.h> /* exit (), EXIT_FAILURE */
-
- int h0, h, x, y;
-
- void a (int), b (int), c (int), d (int);
-
- void inicializar_grafico (void);
-
- #define empezargraf inicializar_grafico ();
- #define plot lineto (x, y)
- #define setplot moveto (x, y);
- #define terminargraf closegraph ();
-
- void main (void)
- {
- const int n = 7;
- int i, x0, y0;
-
- empezargraf;
-
- i = 0;
- h = h0 / 4;
- x0 = 2 * h;
- y0 = 3 * h;
-
- do
- {
- i++;
- x0 -= h;
- h /= 2;
- y0 += h;
- x = x0;
- y = y0;
- setplot;
- A (i); x += h; y -= h; plot;
- B (i); x -= h; y -= h; plot;
- C (i); x -= h; y += h; plot;
- D (i); x += h; y += h; plot;
- /* 27 es el carácter ASCII de la tecla ESCAPE */
- } while (getch () != 27 && i != n);
-
- terminargraf;
- }
-
- void inicializar_grafico (void)
- {
- int gdriver = DETECT, gmode;
- int vpx1, vpy1, vpx2, vpy2;
- int errorcode;
-
- initgraph (&gdriver, &gmode, "");
- errorcode = graphresult ();
-
- if (errorcode != grOk)
- {
- printf ("Error Gráfico: %s\n", grapherrormsg (errorcode));
- getch ();
- exit (EXIT_FAILURE);
- }
-
- h0 = getmaxx () + 1 >= 640 && getmaxy () + 1 >= 480 ? 512 : 128;
-
- /* calcula las coordenadas de viewport para crear un viewport en el centro
- de la pantalla de altura y anchura h0 si puede; esto se hace para que
- el gráfico salga centrado en la pantalla */
- vpx1 = (getmaxx () + 1 - h0) / 2 + 1;
- vpy1 = getmaxy () + 1 <= h0 ? 0 : (getmaxy () + 1 - h0) / 2 + 1;
- vpx2 = vpx1 + h0 - 1;
- vpy2 = getmaxy () + 1 <= h0 ? getmaxy () : vpy1 + h0 - 1;
-
- setviewport (vpx1, vpy1, vpx2, vpy2, 0);
- }
-
- void a (int i)
- {
- if (i > 0)
- {
- a (i-1); x += h; y -= h; plot;
- b (i-1); x += 2 * h; plot;
- d (i-1); x += h; y += h; plot;
- a (i-1);
- }
- }
-
- void b (int i)
- {
- if (i > 0)
- {
- b (i-1); x -= h; y -= h; plot;
- c (i-1); y -= 2 * h; plot;
- a (i-1); x += h; y -= h; plot;
- b (i-1);
- }
- }
-
- void c (int i)
- {
- if (i > 0)
- {
- c (i-1); x -= h; y += h; plot;
- d (i-1); x -= 2 * h; plot;
- b (i-1); x -= h; y -= h; plot;
- c (i-1);
- }
- }
-
- void d (int i)
- {
- if (i > 0)
- {
- d (i-1); x += h; y += h; plot;
- a (i-1); y += 2 * h; plot;
- c (i-1); x -= h; y += h; plot;
- d (i-1);
- }
- }
- ende
- begine " ESPIRAL "
- /*
- Este programa dibuja espirales poligonales aleatorias.
-
- Funciones nuevas del C que aparecen en este ejemplo:
-
- - Librería <conio.h>
-
- · void gotoxy (int x, int y);
- Posiciona cursor en modo texto. Es el equivalente a moveto() en
- modo gráfico. La esquina superior izquierda en modo texto tiene
- coordenadas (1,1) mientras que en modo gráfico tiene coordeandas
- (0,0).
-
- - Librería <graphics.h>:
-
- · int getmaxcol (void);
- Devuelve el máximo color en el modo de gráfico corriente.
-
- · void cleardevice (void);
- Borra pantalla gráfica.
-
- · void setcolor (int color);
- Pone el color de dibujo corriente. El color 0 siempre corresponde al
- negro. Los colores disponibles dependen de la controladora gráfica. La
- función getmaxcol() nos informa del número de colores disponibles.
-
- · void circle (int x, int y, int radio);
- Dibuja un círculo en centro (x,y) y con radio dado.
-
- - Librería <time.h>:
-
- · time_t
- Tipo definido en el fichero time.h. Normalmente suele estar definida
- como long. Este tipo es usado por las funciones de tiempo.
-
- · time_t time (time_t *timer);
- Devuelve el tiempo corriente, en segundos, que ha transcurrido desde
- 00:00:00 GMT, 1 de Enero de 1970, y almacena el valor en el lugar
- apuntado por timer. También devuelve dicho valor.
- El uso más común es:
- time_t t;
- t = time (NULL);
- Al pasar NULL estamos pasando un puntero que no apunta en ningún sitio
- y por lo tanto la función time se limita sólo a devolver el tiempo
- corriente.
-
- - Librería <math.h>:
-
- · double sin (double x);
- Devuelve el seno de x. El argumento x ha de estar en radianes.
-
- · double cos (double x);
- Devuelve el coseno de x. El argumento x ha de estar en radianes.
-
- · double pow (double x, double y);
- Devuelve x elevado a y.
-
- · double atan (double x);
- Devuelve el arco tangente de x.
-
-
- Observaciones que hay en el código fuente:
-
- 1) Recordemos estas dos igualdades matemáticas:
-
- 45° = π / 4
- tg (45°) = 1.0
-
- que son equivalentes a:
-
- π = 4 * 45°
- arctg (1.0) = 45°
-
- lo que nos da:
-
- π = 4 * arctg (1.0)
-
- De esta forma no tenemos que escribir el valor de pi.
-
- 2) Las funciones trigonométricas de la librería <math.h> trabajan con
- radianes, y sin embargo, nuestro programa trabaja con grados. Por
- este motivo necesitamos una constante de conversión de grados sexa-
- gesimales a radianes. Recordar que 360° es equivalente a 2π radianes.
-
- 3) Los bucles de este tipo:
-
- while (kbhit ())
- getch ();
-
- vacían el buffer de teclas. El objetivo de esto es impedir que se
- pueda escribir por adelantado.
- */
-
- #include <stdlib.h> /* randomize (), random (), exit (), EXIT_FAILURE */
- #include <time.h> /* time (), time_t */
- #include <math.h> /* sin (), cos (), pow (), atan () */
- #include <conio.h> /* getch (), kbhit (), getche () */
- #include <graphics.h> /* initgraph (), graphresult (), grOK, grapherrormsg (),
- lineto (), moveto (), cleardevice (), getmaxx (),
- getmaxy (), getmaxcol (), setcolor () */
- #include <stdio.h> /* printf (), NULL, scanf (), puts () */
-
- /* macros: */
-
- #define BOOLEAN int
- #define TRUE 1
- #define FALSE 0
-
- #define ESC 27
- #define ENTER 13
-
- #define NUMESPIRALES 3
-
- #define comparar(l1,l2,l3) ((l1) == (l2) || (l1) == (l3))
- #define entre(x,x1,x2) ((x) >= (x1) && (x) <= (x2))
-
- /* Variables globales: */
-
- int maxx, maxy, maxcol; /* máxima x, máxima y y máximo color */
- BOOLEAN espiral_centrada,
- escribir_con_tecla, escribir_circulos, escribir_valores;
- int segundos_pausa; /* segundos de pausa entre espirales */
- int borrar_pantalla_entre_espirales; /* 0: no, 1: sí, 2: aleatorio */
- int tipo_espiral; /* toma los valores de 0 a 8 */
- double grad; /* constante de conversión grados/radianes */
- double pi; /* número pi */
-
- /* prototipos de funciones: */
-
- BOOLEAN preguntar (void);
- void espiral (void);
-
- /* definición de funciones: */
-
- void prlec5_6 (void)
- {
- int driver = DETECT, modo, codigo_de_error;
- time_t tiempo;
- BOOLEAN salir;
-
- initgraph (&driver, &modo, "");
- codigo_de_error = graphresult ();
- if (codigo_de_error != grOk)
- {
- printf ("Error gráfico: %s\n", grapherrormsg (codigo_de_error));
- printf ("Presiona una tecla para finalizar.");
- getch ();
- exit (EXIT_FAILURE);
- }
- maxx = getmaxx ();
- maxy = getmaxy ();
- maxcol = getmaxcolor ();
- closegraph ();
-
- pi = 4.0 * atan (1.0); /* ver observación 1 */
- grad = pi / 180.0; /* ver observación 2 */
-
- randomize (); /* inicializa el generador de números aleatorios */
-
- while (preguntar ())
- {
- initgraph (&driver, &modo, "");
-
- while (kbhit ()) /* ver observación 3 */
- getch ();
-
- salir = FALSE;
-
- while (! salir)
- {
- espiral (); /* dibuja espiral */
- if (segundos_pausa < 0)
- {
- if (getch () == ESC)
- salir = TRUE;
- }
- else
- {
- tiempo = time (NULL) + segundos_pausa;
- while (! kbhit () && time (NULL) < tiempo)
- ; /* espera la pulsación de una tecla o la consumición de tiempo */
- if (kbhit ())
- if (getch () == ESC)
- salir = TRUE;
- }
- }
-
- if (kbhit ()) /* vacía posibles teclas */
- getch ();
-
- closegraph (); /* vuelve al modo texto */
- }
- }
-
- /*
- Esta función inicializa valores necesarios para el dibujo de la espiral
- y devuelve TRUE para seguir o FALSE para salir del programa
- */
- BOOLEAN preguntar (void)
- {
- char ch;
- BOOLEAN seguir;
-
- /* valores por defecto */
- espiral_centrada = TRUE;
- escribir_con_tecla = escribir_circulos = escribir_valores = FALSE;
- segundos_pausa = 2;
- borrar_pantalla_entre_espirales = 1;
- tipo_espiral = 1;
-
- puts ("PROGRAMA ESPIRAL ");
- printf ("\n¿Valores por defecto (S/N, ENTER: Sí, ESC: Salir)? ");
- do
- {
- ch = getch ();
- } while (ch != ENTER && ch != ESC && ! comparar (ch, 's', 'S') && ! comparar (ch, 'n', 'N'));
- if (ch == ESC)
- seguir = FALSE;
- else
- {
- seguir = TRUE;
- if (comparar (ch, 'n', 'N'))
- {
- printf ("\n¿Centro de la espiral en centro de la pantalla (S/N, ENTER: Sí)? ");
- do
- {
- ch = getch ();
- } while (ch != ENTER && ! comparar (ch, 's', 'S') && ! comparar (ch, 'n', 'N'));
- espiral_centrada = ! comparar (ch, 'n', 'N');
- printf ("\n¿Pausa de 2 segundos entre espiral y espiral (S/N, ENTER: Sí)? ");
- do
- {
- ch = getch ();
- } while (ch != ENTER && ! comparar (ch, 's', 'S') && ! comparar (ch, 'n', 'N'));
- if (comparar (ch, 'n', 'N'))
- {
- printf ("\nIntroduce segundos de pausa entre espirales (< 0 para esperar tecla): ");
- scanf ("%d", &segundos_pausa);
- }
- printf ("\n¿Escribir espiral mediante pulsación de tecla (S/N, ENTER: No)? ");
- do
- {
- ch = getch ();
- } while (ch != ENTER && ! comparar (ch, 's', 'S') && ! comparar (ch, 'n', 'N'));
- escribir_con_tecla = comparar (ch, 's', 'S');
- printf ("\n¿Escribir valores de algunas variables en dibujo (S/N, ENTER: No)? ");
- do
- {
- ch = getch ();
- } while (ch != ENTER && ! comparar (ch, 's', 'S') && ! comparar (ch, 'n', 'N'));
- escribir_valores = comparar (ch, 's', 'S');
- printf ("\n¿Escribir también círculos de radio aleatorio (S/N, ENTER: No)?: ");
- do
- {
- ch = getch ();
- } while (ch != ENTER && ! comparar (ch, 's', 'S') &&
- ! comparar (ch, 'n', 'N') && ! comparar (ch, 'a', 'A'));
- escribir_circulos = comparar (ch, 's', 'S');
- printf ("\n¿Borrar pantalla entre espirales (S o ENTER: Sí, N: No, A: Aleatorio)?: ");
- do
- {
- ch = getch ();
- } while (ch != ENTER && ! comparar (ch, 's', 'S') &&
- ! comparar (ch, 'n', 'N') && ! comparar (ch, 'a', 'A'));
- borrar_pantalla_entre_espirales = ch == ENTER || comparar (ch, 's', 'S') ? 1 :
- comparar (ch, 'n', 'N') ? 0 : 2;
- puts ("\nTipos de espirales (r: radio, a: ángulo):");
- puts (" 0: espiral aleatoria entre una de las 8 siguientes");
- puts (" 1: x = r * seno (a); y = r * coseno (a)");
- puts (" 2: x = r * coseno(a)*coseno(a)*coseno(a); y = r * seno(a)*seno(a)*seno(a)");
- puts (" 3: exponente1 y exponente2 aleatorios, 0 ≤ exponente1, exponente2 ≤ 3,");
- puts (" exponente1 + exponente2 es un número impar;");
- puts (" x = r * potencia(seno(a),exponente1) * potencia(coseno(a)*exponente2);");
- puts (" x = r * potencia(seno(a),exponente2) * potencia(coseno(a)*exponente1);");
- puts (" [las funciones 1 y 2 son un caso particular de esta funión]");
- printf ("\nIntroduce número correspondiente al tipo de espiral (0-8, ENTER: 0): ");
- do
- {
- ch = getch ();
- } while (ch != ENTER && ! entre (ch, '0', '0' + NUMESPIRALES));
- tipo_espiral = ch == ENTER ? 0 : ch - '0';
- }
- }
-
- return (seguir);
- }
-
- /*
- Dibuja espiral.
- */
- void espiral (void)
- {
- double radio, angulo;
- double incr_radio, incr_angulo;
- double seno, coseno;
- int x, y;
- int tipo_espiral_local;
- int centrox, centroy; /* coordenadas del centro de la pantalla */
- int exponente1, exponente2;
- int radio_circulo;
-
- incr_angulo = random (3600) / 10.0; /* 0.0 ≤ incr_angulo ≤ 359.9 */
- incr_radio = 1.0 + random (300) / 100.0; /* 1.0 ≤ incr_radio ≤ 3.99 */
-
- radio = angulo = 0.0;
-
- if (escribir_circulos)
- radio_circulo = 1 + random (maxy / 2); /* 1 ≤ radio_circulo ≤ maxy / 2*/
-
- if (espiral_centrada)
- {
- centrox = (maxx + 1) / 2;
- centroy = (maxy + 1) / 2;
- x = centrox;
- y = centroy;
- }
- else
- {
- x = maxx;
- y = maxy;
- }
-
- setcolor (1 + random (maxcol)); /* genera color disponible excepto el 0 (negro) */
-
- if (borrar_pantalla_entre_espirales == 1 ||
- borrar_pantalla_entre_espirales == 2 && random (2))
- cleardevice ();
-
- tipo_espiral_local = tipo_espiral == 0 ? random (NUMESPIRALES) + 1 : tipo_espiral;
- if (tipo_espiral_local == 3)
- {
- exponente1 = random (4);
- exponente2 = random (4);
- if ((exponente1 + exponente2) % 2 == 0)
- (random (2) ? exponente1 : exponente2)++;
- }
-
- moveto (x, y);
-
- while ((espiral_centrada && (x >= 0 && x <= getmaxx () || y >= 0 && y <= getmaxy ())) ||
- (! espiral_centrada && (x > 0 || y > 0)))
- {
- radio += incr_radio;
- angulo += incr_angulo;
-
- seno = sin (angulo * grad);
- coseno = cos (angulo * grad);
-
- switch (tipo_espiral_local)
- {
- case 1:
- x = (espiral_centrada ? centrox : x) + radio * seno;
- y = (espiral_centrada ? centroy : y) + radio * coseno;
- break;
- case 2:
- x = (espiral_centrada ? centrox : x) + radio * (coseno * coseno * coseno);
- y = (espiral_centrada ? centroy : y) + radio * (seno * seno * seno);
- break;
- case 3:
- x = (espiral_centrada ? centrox : x) + radio * pow (seno, exponente1) * pow (coseno, exponente2);
- y = (espiral_centrada ? centroy : y) + radio * pow (seno, exponente2) * pow (coseno, exponente1);
- break;
- }
- if (escribir_con_tecla)
- getch ();
- lineto (x, y);
- if (escribir_circulos)
- circle (x, y, radio_circulo);
- }
-
- if (escribir_valores)
- {
- gotoxy (1, 1);
- printf ("Incremento del ángulo: %lg\n", incr_angulo);
- printf ("Incremento del radio: %lg\n", incr_radio);
- if (escribir_circulos)
- printf ("Radio del círculo: %d\n", radio_circulo);
- }
- }
- ende
- begine " POLIGONO "
- /*
- Dibuja un polígono de una forma recursiva.
-
- Al polígono que dibuja este programa también se le llama fractal ya que
- está definido en términos recursivos y su aspecto es siempre el mismo
- independientemente de su tamaño.
-
- Todas las funciones utilizadas ya han sido explicadas en ejemplos anteriores
- y en teoría. En cuanto a la lógica del programa es muy simple y se entiende
- enseguida.
- */
-
- /* Ficheros a incluir: */
-
- #include <stdio.h> /* printf (), puts (), scanf () */
- #include <math.h> /* atan () */
- #include <conio.h> /* getch (), kbhit () */
- #include <stdlib.h> /* exit (), EXIT_FAILURE, EXIT_SUCCESS */
- #include <graphics.h> /* initgraph (), graphresult (), grOK, grapherrormsg (),
- closegraph (), DETECT, lineto (), moveto () */
-
- /* macros: */
-
- #define ESC 27
- #define BOOLEAN int
- #define TRUE 1
- #define FALSE 0
-
- /* variables globales: */
-
- double rad_a_grad;
- double posx, posy;
-
- /* prototipos de las funciones utilizadas: */
-
- BOOLEAN leer_datos (int *numero_de_lados, int *orden);
- void dibuja_poligono (int numero_de_lados, int orden);
- void dibuja_lado (double la, double ang, int n);
- void dibuja_linea (double lon, double a);
-
- /* definición de las funciones: */
-
- /*
- Función principal
- */
-
- void main (void)
- {
- int numero_de_lados_poligono, orden_poligono;
- int driver = DETECT, modo, codigo_de_error;
- char ch;
-
- initgraph (&driver, &modo, "");
- codigo_de_error = graphresult();
- if (codigo_de_error != grOk)
- {
- printf ("Error gráfico: %s\n", grapherrormsg (codigo_de_error));
- printf ("Presiona un tecla para finalizar.");
- getch ();
- exit (EXIT_FAILURE);
- }
-
- /* ver el significado de esta variable en la variable grad del ejemplo
- anterior: espiral */
- rad_a_grad = atan (1.0) / 45.0;
-
- closegraph ();
- while (leer_datos (&numero_de_lados_poligono, &orden_poligono))
- {
- initgraph (&driver, &modo, "");
- dibuja_poligono (numero_de_lados_poligono, orden_poligono);
- ch = getch ();
- closegraph ();
- if (ch == ESC) /* salir con exit() sin hacer closegraph() es desastroso */
- exit (EXIT_SUCCESS);
- }
-
- closegraph ();
- }
-
- /*
- Lee las características del polígono y permite abandonar el programa.
- */
-
- BOOLEAN leer_datos (int *numero_de_lados, int *orden)
- {
- BOOLEAN seguir;
-
- puts ("POLIGONO RECURSIVO");
- puts ("\nPara salir del programa durante la traza del dibujo, pulsar ESC.");
- do
- {
- printf ("\nIntroduce número de lados del polígono (≥ 1, 0 para salir): ");
- scanf ("%d", numero_de_lados); /* no sería correcto &numero_de_lados porque
- numero_de_lados ya es un puntero */
- } while (*numero_de_lados < 0);
- if (*numero_de_lados == 0)
- seguir = FALSE;
- else
- {
- seguir = TRUE;
- do
- {
- printf ("\nIntroduce orden del polígono (≥ 1): ");
- scanf ("%d", orden);
- } while (*orden < 1);
- }
- return (seguir);
- }
-
- /*
- Dibuja un polígono de un cierto número de lados y de un cierto orden
- */
-
- void dibuja_poligono (int numero_de_lados, int orden)
- {
- register int i;
- double lado, angulo;
-
- /*
- el siguiente if es para que la figura salga más o menos centrada en
- la pantalla
- */
- if (numero_de_lados == 1 || numero_de_lados == 2)
- {
- lado = getmaxy () / 2;
- posx = getmaxx () / 2.0 + (lado / 2) * (numero_de_lados == 1 ? -1 : 1);
- posy = getmaxy () / 2.0;
- }
- else
- {
- lado = getmaxy () / numero_de_lados;
- posx = getmaxx () / 2.0 + lado / 2;
- posy = getmaxy () / 2.0 - lado;
- }
- moveto ((int) posx, (int) posy);
- angulo = 360.0 / numero_de_lados;
- for (i = 1; i <= numero_de_lados; i++)
- dibuja_lado (lado, -angulo * i, orden);
- }
-
- /*
- Dibuja un lado recursivo hacia el ángulo angulo y de orden ord
- */
-
- void dibuja_lado (double lado, double angulo, int ord)
- {
- if (ord <= 1)
- dibuja_linea (lado, angulo);
- else
- {
- lado /= 3.0;
- ord--;
- /* cada lado consta de 4 líneas; se puede modifica el número de líneas
- de cada lado para hacer otras figuras */
- dibuja_lado (lado, angulo, ord);
- dibuja_lado (lado, angulo + 60, ord);
- dibuja_lado (lado, angulo - 60, ord);
- dibuja_lado (lado, angulo, ord);
- }
- }
-
- /*
- Dibuja una línea de longitud lon desde la posición actual hacia el
- ángulo a
- */
-
- void dibuja_linea (double lon, double a)
- {
- posx += (lon * cos (a * rad_a_grad));
- posy -= (lon * sin (a * rad_a_grad));
-
- if (kbhit () && getch () == ESC) /* la comparación getch()==ESC sólo se ... */
- exit (EXIT_SUCCESS); /* ... hace si se cumple la primera condición: kbhit() */
- lineto ((int) posx, (int) posy);
- }
- ende
- endt
- end lección 6
-
- ; LECCION 6
- begin
- begine " TRES EN RAYA "
- /*
- Programa que permite jugar al usuario a las tres en raya con la computadora.
-
- El programa representa la matriz de tres en raya como un array de caracteres
- de 3 por 3. El jugador siempre es X y la computadora O.
-
- Cuando mueve el jugador, el carácter X se coloca en la posición especificada
- de la matriz. Cuando le toca mover a la computadora, recorre la matriz y pone
- O en la primera posición vacía de la matriz. Si no encuentra una posición
- vacía, lo indica y sale.
- */
-
- #include <stdio.h> /* printf (), scanf () */
- #include <stdlib.h> /* exit () */
- #include <conio.h> /* getch () */
-
- #define ESPACIO ' '
-
- char matriz[3][3] =
- {
- ESPACIO, ESPACIO, ESPACIO,
- ESPACIO, ESPACIO, ESPACIO,
- ESPACIO, ESPACIO, ESPACIO
- };
-
- void obtener_movimiento_de_jugador (void);
- void obtener_movimiento_de_computadora (void);
- void mostrar_matriz (void);
- char comprobar (void);
-
- void main (void)
- {
- char hecho = ESPACIO;
-
- printf ("JUEGO DE LAS TRES EN RAYA.\n\n");
-
- do
- {
- mostrar_matriz ();
- obtener_movimiento_de_jugador ();
- hecho = comprobar (); /* ver si gana el jugador */
- if (hecho != ESPACIO)
- break;
- obtener_movimiento_de_computadora ();
- hecho = comprobar (); /* ver si gana la computadora */
- } while (hecho == ESPACIO);
-
- if (hecho == 'X')
- printf ("\n¡HAS GANADO!\n");
- else
- printf ("\n¡YO GANO!\n");
-
- mostrar_matriz (); /* mostrar las posiciones finales */
- printf ("\n\nPulsa cualquier tecla para finalizar. ");
- getch ();
- }
-
- void obtener_movimiento_de_jugador (void)
- {
- int x, y;
-
- printf ("\nIntroduzca sus coordenadas de la X (1≤fila≤3, 1≤columna≤3): ");
- scanf ("%d%d", &x, &y);
- x--;
- y--;
- if (matriz[x][y] != ESPACIO)
- {
- printf ("Movimiento inválido, prueba de nuevo.\n");
- obtener_movimiento_de_jugador ();
- }
- else
- matriz[x][y] = 'X';
- }
-
- void obtener_movimiento_de_computadora (void)
- {
- int encontrado = 0;
- register int i, j;
-
- for (i = 0; ! encontrado && i < 3; i++)
- for (j = 0; ! encontrado && j < 3; j++)
- if (matriz[i][j] == ESPACIO)
- encontrado = 1;
-
- if (encontrado)
- matriz[i-1][j-1] = 'O';
- else
- {
- printf ("Tablero completo.\n");
- exit (0);
- }
- }
-
- void mostrar_matriz (void)
- {
- register int i;
-
- printf ("\n 1 2 3");
- printf ("\n ┌───┬───┬───┐");
- for (i = 0; i < 3; i++)
- {
- printf ("\n%d │ %c │ %c │ %c │", i+1, matriz[i][0], matriz[i][1], matriz[i][2]);
- if (i != 2)
- printf ("\n ├───┼───┼───┤");
- }
- printf ("\n └───┴───┴───┘");
- }
-
- char comprobar (void)
- {
- register int t;
-
- /* comprobar filas */
- for (t = 0; t < 3; t++)
- if (matriz[t][0] == matriz[t][1] && matriz[t][1] == matriz[t][2])
- return matriz[t][0];
-
- /* comprobar columnas */
- for (t = 0; t < 3; t++)
- if (matriz[0][t] == matriz[1][t] && matriz[1][t] == matriz[2][t])
- return matriz[0][t];
-
- /* comprobar diagonal principal */
- if (matriz[0][0] == matriz[1][1] && matriz[1][1] == matriz[2][2])
- return matriz[0][0];
-
- /* comprobar diagonal inversa */
- if (matriz[0][2] == matriz[1][1] && matriz[1][1] == matriz[2][0])
- return matriz[0][2];
-
- return ESPACIO;
- }
- ende
- begine " CUADRADO MAGICO "
- /*
- Este programa genera e imprime un cuadrado mágico de dimensión N (siendo N
- un número entero, positivo e impar).
-
- Un cuadrado mágico de dimensión N es una matriz cuadrada de orden N,
- conteniendo los números naturales de 1 a N*N, tal que coinciden la suma
- de los números de una cualquiera de las filas o columnas, o de una de
- las diagonales principales.
-
- El cuadrado se construye mediante las siguientes reglas:
-
- - El número 1 se coloca en la casilla central de la primera fila.
- - Cada número siguiente se coloca en la casilla correspondiente a la
- fila anterior y columna posterior.
- - Si el número sigue a un múltiplo de N, no se aplica la regla anterior,
- sino que se coloca en la casilla de la fila posterior e igual columna.
- - Se considera que la fila anterior a la primera es la última, y la
- columna posterior a la última es la primera.
-
- Una observación acerca de la implementación de este programa: En la declara-
- ción de la matriz se ha puesto MAXIMA_DIMENSION+1 porque los elementos de
- la matriz correspondientes a los índices 0 se han despreciado; con esto se
- ha perseguido hacer la lógica del programa más simple.
- */
-
- #include <stdio.h> /* printf (), scanf () */
- #include <conio.h> /* getch () */
-
- #define MAXIMA_DIMENSION 19
-
- void main (void)
- {
- int matriz[MAXIMA_DIMENSION+1][MAXIMA_DIMENSION+1];
- int dimension, numero, fila, columna;
-
- printf ("CUADRADO MAGICO\n\n");
- do
- {
- printf ("Introduce dimensión (impar y entre 1-%d): ", MAXIMA_DIMENSION);
- scanf ("%d", &dimension);
- } while (dimension % 2 == 0 || dimension < 1 || dimension > MAXIMA_DIMENSION);
-
- fila = 1;
- columna = dimension / 2 + 1;
- for (numero = 1; numero <= dimension * dimension; numero++)
- {
- matriz[fila][columna] = numero;
- if (numero % dimension == 0)
- fila++;
- else
- {
- fila = fila == 1 ? dimension : fila - 1;
- columna = columna == dimension ? 1 : columna + 1;
- }
- }
-
- printf ("\nEl cuadrado mágico de dimensión %d es:\n\n", dimension);
- for (fila = 1; fila <= dimension; fila++)
- {
- for (columna = 1; columna <= dimension; columna++)
- printf ("%4d", matriz[fila][columna]);
- printf ("\n");
- }
-
- printf ("\nPulsa una tecla para finalizar.");
- getch ();
- }
- ende
- begine " MEJOR DESGLOSE DE MONEDA "
- /*
- Este programa recibe como dato un número entero positivo, correspondiente
- a una cantidad de dinero, y calcula e imprime el mejor desglose de moneda
- (mínimo número de unidades monetarias).
-
- Las unidades monetarias existentes son:
-
- 10000, 5000, 2000, 1000, 500, 200, 100, 50, 25, 10, 5, 2, 1.
-
- El programa almacenará estas cantidades ordenadas en un vector y desglosará
- la cantidad en orden creciente de las componentes del vector.
- */
-
- void main (void)
- {
- int unidades [] =
- { 10000, 5000, 2000, 1000, 500, 200, 100, 50, 25, 10, 5, 2, 1 };
- int i;
- long cantidad, num;
-
- printf ("DESGLOSE DE MONEDA\n\n");
- printf ("Las unidades monetarias son:\n");
- printf ("10000, 5000, 2000, 1000, 500, 200, 100, 50, 25, 10, 5, 2, 1.\n\n");
- printf ("Escribe la cantidad a desglosar (<= 0 para terminar): ");
- scanf ("%ld", &cantidad);
- while (cantidad > 0)
- {
- i = -1;
- while (cantidad > 0)
- {
- if ((num = cantidad / unidades[++i]) > 0)
- printf (" %ld %s%s de %d\n", num,
- unidades[i] <= 500 ? "moneda" : "billete",
- num == 1 ? "" : "s", unidades[i]);
- cantidad -= num * unidades[i];
- }
- printf ("\nEscribe la cantidad a desglosar (<= 0 para terminar): ");
- scanf ("%ld", &cantidad);
- }
- }
- ende
- begine " METODO DE ELIMINACION DE GAUSS "
- /*
- El objetivo de este programa es ejecutar el método de eliminación de Gauss
- sobre un sistema de ecuaciones introducido por el usuario.
-
- METODO DE ELIMINACION DE GAUSS PARA LA RESOLUCION DE SISTEMAS DE ECUACIONES:
-
- En muchísimos cálculos científicos y de ingeniería, las soluciones a un
- problema se presentan en forma de sistema de ecuaciones con varias incóg-
- nitas. Un ejemplo de sistema sería:
-
- x1 + 2 x2 - x3 = 2
- 5 x1 + 12 x2 + x3 = 32
- 3 x1 + 9 x2 + x3 = 24
-
- En este caso se trata de un sistema de tres ecuaciones con tres incógnitas.
- Los números por los que se multiplican las incógnitas se llaman coeficientes,
- y constantes los que ocupan los miembros derechos de las ecuaciones. En
- general, puede haber sistemas con cualquier número de ecuaciones y el mismo
- número de incógnitas. Algunos de estos sistemas no tienen solución, y otros
- tienen muchas. Aquí nos limitaremos a los sistemas "bien educados", con una
- solución única que es el conjunto de valores de las incógnitas que satisface
- todas las ecuaciones. Por razones de simplicidad, en los ejemplos haremos
- referencia únicamente a sistemas de tres ecuaciones con tres incógnitas.
-
- Hay varias técnicas de resolución de sistemas de ecuaciones. La de eliminación
- de Gauss es muy sencilla, pero a la vez muy potente. No se trata de un número
- de aproximación, y funciona con sistemas de cualquier número de ecuaciones y
- el mismo número de incógnitas. Admite pruebas para interrumpir el proceso si
- el sistema carece de solución. En el método de eliminación de Gauss, los coe-
- ficientes y las constantes se consideran como elementos de una matriz; el
- proceso tiene dos fases:
-
- En primer lugar se restan sistemáticamente múltiplos de unas ecuaciones (o
- filas de matries) a otras hasta crear una matriz triangular en la que todos
- los elementos situados por debajo de la diagonal principal sean nulos.
-
- En segundo lugar se procede a la restitución, partiendo de la fila inferior
- y avanzando hacia arriba, hasta obtener los valores de todas las incógnitas.
-
- Apliquemos este método al ejemplo anterior:
-
- x1 + 2 x2 - x3 = 2 (1)
- 5 x1 + 12 x2 + x3 = 32 (2)
- 3 x1 + 9 x2 + x3 = 24 (3)
-
- El primer paso es eliminar los coeficientes segundo y tercero de la primera
- columna. Para ello se substrae a la segunda ecuación la primera multiplicada
- por 5, y a la tercera también la primera multiplicada por 3:
-
- x1 + 2 x2 - x3 = 2 (1)
- (2) -5 * (1) 2 x2 + 6 x3 = 22 (4)
- (3) -3 * (1) 3 x2 + 4 x3 = 18 (5)
-
- A continuación se elimina el último coeficiente de la segunda columna restando
- a la tercera ecuación la segunda multiplicada por 3/2:
-
- x1 + 2 x2 - x3 = 2 (1)
- 2 x2 + 6 x3 = 22 (4)
- (5) - 3/2 * (4) - 5 x3 = -15 (6)
-
- Ahora los coeficientes de las ecuaciones forman ya una matriz triangular. El
- proceso de restitución empieza, pues, por la tercera ecuación:
-
- x3 = (-15) / (-5) = 3
- x2 = (22 - 6 x3) / 2 = (22 - 6 * 3) / 2 = 2
- x1 = (2 - 2 x2 + x3) / 1 = (2 - 2 * 2 + 3) / 1 = 1
-
- La solución es, pues;
-
- x1 = 1, x2 = 2, x3 = 3.
-
- PROGRAMACION DEL METODO DE GAUSS:
-
- En el programa, los coeficientes y las constantes pasan a convertirse en
- elementos de una matriz, identificados mediante dos subíndices:
-
- a11 x1 + a12 x2 + a13 x3 = a14
- a21 x1 + a22 x2 + a23 x3 = a24
- a31 x1 + a32 x2 + a33 x3 = a34
-
- Como todas las operaciones se ejecutarán sobre los elementos de la matriz,
- pueden omitirse las incógnitas:
-
- a11 a12 a13 a14
- a21 a22 a23 a24
- a31 a32 a33 a34
-
- Sean aij el elemento general de la matriz, situado en la fila i y la
- columna j. En general, la matriz tendrá n filas y n+1 columnas.
-
- El algoritmo de creación de la matriz triangular sobre la diagonal prin-
- cipal es el siguiente:
-
- Para k = 1 hasta n - 1, repetir el proceso:
- Para i = k + 1 hasta n, repetir el proceso:
- Hacer el multiplicador m = aik / akk.
- Para j = k hasta n + 1, repetir el proceso:
- Hacer aij = aij - m * akj.
-
- El proceso de restitución queda descrito por este otro algoritmo:
-
- Para k = n hasta 1 en pasos de -1, repetir el proceso:
- Hacer el substraendo s = 0.
- Para j = k + 1 hasta n, repetir el proceso:
- Hacer s = s + akj * xj.
- Hacer xk = (akn+1 - s) / akk.
-
- Observa que la repetición del bucle interno ocurre cero veces si k = n.
-
- OBSERVACION SOBRE ESTA IMPLEMENTACION C:
-
- En C, los índices de los arrays empiezan por 0; sin embargo, la lógica
- está pensada a partir de 1.
-
- La solución para esto es:
-
- int x[N];
-
- #define X(i) (x[i-1])
-
- De esta forma, cuando hacemos:
-
- X(1);
-
- estamos haciendo, en realidad, esto:
-
- x[0];
- */
-
- #include <stdio.h> /* printf (), scanf (), puts (), getch () */
- #include <stdlib.h> /* exit () */
-
- void main (void)
- {
- /* MACROS */
- #define NUMERO_MAXIMO_DE_INCOGNITAS 10
- #define M(fila,columna) (matriz[fila-1][columna-1])
- #define X(incognita) (incognitas[incognita-1])
-
- /* VARIABLES LOCALES */
- float matriz[NUMERO_MAXIMO_DE_INCOGNITAS][NUMERO_MAXIMO_DE_INCOGNITAS+1],
- incognitas[NUMERO_MAXIMO_DE_INCOGNITAS];
- register int i, j, k;
- int n;
- float m, s; /* multiplicando y substraendo */
-
- /* IMPRESION DEL TITULO DEL PROGRAMA */
- puts ("RESOLUCION DE UN SISTEMA DE ECUACIONES POR EL METODO DE ELIMINACION DE GAUSS\n");
-
- /* RELLENO DE LA MATRIZ */
- do
- {
- printf ("Introduce número de incógnitas (1-%d): ",
- NUMERO_MAXIMO_DE_INCOGNITAS);
- scanf ("%d", &n);
- } while (n < 1 || n > NUMERO_MAXIMO_DE_INCOGNITAS);
- for (i = 1; i <= n; i++)
- {
- printf ("Introduce los %d coeficientes de la fila %d: ", n + 1, i);
- for (j = 1; j <= n + 1; j++)
- {
- float faux;
- scanf ("%g", &faux);
- M (i, j) = faux;
- }
- }
-
- /* IMPRESION DEL SISTEMA ECUACIONES INTRODUCIDO */
- puts ("\nEL SISTEMA DE ECUACIONES INTRODUCIDO ES:");
- for (i = 1; i <= n; i++)
- {
- j = 1;
- printf (" %g x%d ", M (i, j), j);
- for (j++; j <= n; j++)
- printf ("%c %g x%d ", M (i, j) < 0 ? '-' : '+',
- M (i, j) < 0 ? - M (i, j) : M (i, j), j);
- printf ("= %g\n", M (i, j));
- }
-
- /* CREACION DE UNA MATRIZ TRIANGULAR SOBRE LA DIAGONAL PRINCIPAL */
- for (k = 1; k <= n - 1; k++)
- for (i = k + 1; i <= n; i++)
- {
- if (M (k, k) == 0)
- {
- puts ("\nNo se puede resolver el problema por este método.");
- getch ();
- exit (0);
- }
- m = M (i, k) / M (k, k);
- for (j = k; j <= n + 1; j++)
- M (i, j) = M (i, j) - m * M (k ,j);
- }
-
- /* RESTITUCION */
- for (k = n; k >= 1; k--)
- {
- s = 0;
- if (k + 1 <= n)
- for (j = k + 1; j <= n; j++)
- s += M (k, j) * X (j);
- if (M (k ,k) == 0)
- {
- puts ("\nNo se puede resolver el problema por este método.");
- getch ();
- exit (0);
- }
- X (k) = (M (k, n + 1) - s) / M (k, k);
- }
-
- /* IMPRESION DE LA SOLUCION DEL SISTEMA DE ECUACIONES */
- puts ("\nLA SOLUCION DEL SISTEMA ES:");
- for (i = 1; i <= n; i++)
- printf (" x%d = %g\n", i, X (i));
-
- puts ("\nPulsa una tecla para finalizar.");
- getch ();
-
- #undef X
- #undef M
- #undef DIMENSION_MAXIMA
- }
- ende
- begine " JUEGO DEL RATON ATRAPADO "
- /*
- Tenemos una matriz de 20x20. A los elementos del contorno los vamos a
- llamar -1 y tienen el significado de agua. En cada extremo va a haber
- un elemento con valor 1 que tiene el significado de salida o puente. El
- resto de las casillas van a tener el valor de 0. El programa pondrá un
- ratón en una posición aleatoria de la matriz y este ratón se irá moviendo
- aleatoriamente por la matriz hasta caer al agua, hasta salir por un
- puente o hasta dar 100 movimientos (en este caso el ratón se muere de
- hambre). Además también escribiremos una matriz de 20x20 que nos va a
- informar el número de veces que ha pasado el ratón por los elementos de
- la primera matriz.
- */
-
- #include <stdio.h> /* printf () */
- #include <conio.h> /* getch () */
- #include <stdlib.h> /* random () */
-
- #define DIMENSION 20
-
- #define BOOLEAN int
- #define TRUE 1
- #define FALSE 0
-
- void inicializar (int m[][DIMENSION], int mapa[][DIMENSION], int *px, int *py,
- BOOLEAN *pahogado, BOOLEAN *pescapado,
- int *pnumero_de_movimientos);
- void mover (int movimiento, int *px, int *py);
- void comprobar (int m[][DIMENSION], int mapa[][DIMENSION], int x, int y,
- BOOLEAN *pahogado, BOOLEAN *pescapado,
- int *pnumero_de_movimientos);
- void finalizar (int m[][DIMENSION], int mapa[][DIMENSION], int x, int y,
- BOOLEAN ahog, BOOLEAN escap);
-
- void main (void)
- {
- int x, y, numero_de_movimientos, matriz[DIMENSION][DIMENSION],
- mapa_matriz[DIMENSION][DIMENSION];
- BOOLEAN ahogado, escapado;
-
- inicializar (matriz, mapa_matriz, &x, &y, &ahogado, &escapado,
- &numero_de_movimientos);
- while (numero_de_movimientos < 100 && ! ahogado && ! escapado)
- {
- mover (random (4) + 1, &x, &y);
- comprobar (matriz, mapa_matriz, x, y,
- &ahogado, &escapado, &numero_de_movimientos);
- }
- finalizar (matriz, mapa_matriz, x, y, ahogado, escapado);
- }
-
- void inicializar (int m[][DIMENSION], int mapa[][DIMENSION], int *px, int *py,
- BOOLEAN *pahogado, BOOLEAN *pescapado,
- int *pnumero_de_movimientos)
- {
- register int i, j;
-
- for (i = 0; i < DIMENSION; i++)
- for (j = 0; j < DIMENSION; j++)
- m[i][j] = mapa[i][j] = 0;
-
- for (i = 0; i < DIMENSION; i++)
- m[0][i] = m[DIMENSION-1][i] = m[i][0] = m[i][DIMENSION-1] = -1;
-
- m[0][random (DIMENSION)] = m[DIMENSION-1][random (DIMENSION)] =
- m[random (DIMENSION)][0] = m[random (DIMENSION)][DIMENSION-1] = 1;
-
- *pahogado = *pescapado = FALSE;
- *pnumero_de_movimientos = 0;
-
- *px = random (DIMENSION);
- *py = random (DIMENSION);
-
- comprobar (m, mapa, *px, *py, pahogado, pescapado, pnumero_de_movimientos);
- }
-
- void mover (int movimiento, int *px, int *py)
- {
- switch (movimiento)
- {
- case 1: --*px; break;
- case 2: --*py; break;
- case 3: ++*px; break;
- case 4: ++*py; break;
- }
- }
-
- void comprobar (int m[][DIMENSION], int mapa[][DIMENSION], int x, int y,
- BOOLEAN *pahogado, BOOLEAN *pescapado,
- int *pnumero_de_movimientos)
- {
- if (m[x][y] == -1)
- *pahogado = TRUE;
- else if (m[x][y] == 1)
- *pescapado = TRUE;
- ++mapa[x][y];
- ++*pnumero_de_movimientos;
- }
-
- void finalizar (int m[][DIMENSION], int mapa[][DIMENSION], int x, int y,
- BOOLEAN ahog, BOOLEAN escap)
- {
- register int i, j;
-
- printf ("Matriz:\n");
- printf ("(#: agua; : salida; *: ha pasado el ratón; .: no ha pasado el ratón)\n\n");
- for (i = 0; i < DIMENSION; i++)
- {
- for (j = 0; j < DIMENSION; j++)
- printf ("%3c", m[i][j] == -1 ? '#' : m[i][j] == 1 ? '' :
- mapa[i][j] == 0 ? '.' : '*');
- printf ("\n");
- }
-
- printf ("\nPulsa una tecla para continuar.");
- getch ();
-
- puts ("\nMapa:\n");
- for (i = 0; i < DIMENSION; i++)
- {
- for (j = 0; j < DIMENSION; j++)
- printf ("%3d", mapa[i][j]);
- printf ("\n");
- }
-
- printf ("\nPosición final: (%d, %d): ", x, y);
-
- if (escap)
- printf ("RATON SALVADO.\n");
- else if (ahog)
- printf ("RATON AHOGADO.\n");
- else
- printf ("RATON MUERTO DE HAMBRE.\n");
-
- printf ("Pulsa una tecla para finalizar.");
- getch ();
- }
- ende
- begine " 32 FUNCIONES DE MANIPULACION DE ARRAYS DE CARACTERES "
- /*
- Este programa consta de 32 funciones sobre manipulación de cadenas (arrays
- de caracteres) y la función main para probar las funciones mencionadas.
-
- Hay dos cosas importantes que comentar:
-
- 1) Función borrar_pantalla. Hay dos versiones de esta función:
-
- - Para los usuarios de Turbo C, la función borrar pantalla es clrscr
- (clear screen) cuyo prototipo se encuentra en el fichero stdlib.h:
- void clrscr (void);
-
- - Para los usuarios que compilen este programa en otro compilador, se
- define la función completa utilizando la función int86() que se encuentra
- en la librería <dos.h>. Tanto la librería <dos.h> como la función
- int86() como el contenido de nuestra función borrar_pantalla() se
- explicará en lecciones posteriores. Lo único que tiene que saber el
- usuario, en este momento, es que la función borrar_pantalla borra la
- pantalla de texto actual como su propio nombre indica, y no importa
- ahora mismo cómo está implementada.
-
- La macro predefinida __TURBOC__ sólo está definida en los compiladores
- de Turbo C, por lo tanto, la expresión
- #ifdef __TURBOC__
- será cierta para los preprocesadores de Turbo C y falsa (se ejecuta
- el #else en este caso) para aquellos preprocesadores que no son de
- Turbo C.
-
- 2) Funciones calloc y free. Estas dos funciones se encuentran en la
- librería <alloc.h>. La primera función asigna memoria y la segunda
- libera la memoria asignada. Las dos funciones se explicarán en
- lecciones posteriores; lo único que necesitas saber en este momento
- para comprender el programa es que calloc se utiliza de la siguiente
- forma en nuestro ejemplo:
-
- {
- char *p;
- p = (char *) calloc (1, 10);
- if (p == 0)
- error ();
- /* ahora se puede utilizar p como un array: p[indice] */
- /* ... */
- free (p); /* aquí se libera memoria asignada para p */
- }
-
- Las sentencias anteriores son, a efectos prácticos, equivalentes a:
-
- {
- char p[10];
- /* ... */
- } /* aquí se libera memoria asinada para p */
-
- En el primer caso, la cantidad de memoria a reservar se calcula en
- tiempo de ejecución y en el segundo se calcula en tiempo de compilación.
-
- Insisto, en este momento he explicado lo mínimo que hay que saber sobre
- las funciones calloc() y free() para entender el ejemplo. En lecciones
- ulteriores se estudiarán estas funciones en detalle.
- */
-
- /* Ficheros a incluir: */
-
- #include <stdio.h> /* printf (), puts (), scanf (), gets () */
- #include <alloc.h> /* calloc(), free () */ /* ver observación 2 al principio */
- #include <conio.h> /* clrscr () si TURBO C, putch (), getch () */
- #include <dos.h> /* int86 (), union REGS */ /* ver obsev. 1 al principio */
-
- /* Compilación condicional: */
-
- #ifdef __TURBOC__ /* ver observación 1 en comentario inicial */
- #define borrar_pantalla clrscr
- #else
- void borrar_pantalla (void) /* sólo hay que saber de esta función, en este momento, ... */
- { /* ... que borra la pantalla, no qué significa estas sentecias */
- union REGS regs;
- regs.h.ah = 6; /* código de desplazamiento de la pantalla */
- regs.h.al = 0; /* código de borrar la pantalla */
- regs.h.ch = 0; /* fila inicial */
- regs.h.cl = 0; /* columna inicial */
- regs.h.dh = 24; /* fila final */
- regs.h.dl = 79; /* columna final */
- regs.h.bh = 7; /* la línea de borrado en negra */
- int86 (0x10, ®s, ®s);
- regs.h.ah = 2; /* función de direccionamiento del cursor */
- regs.h.dl = 0; /* coordenada de la columna */
- regs.h.dh = 0; /* coordenada de la fila */
- regs.h.bh = 0; /* página de vídeo */
- int86 (0x10, ®s, ®s);
- }
- #endif
-
- /* Prototipos de funciones utilizadas: */
-
- int longitud_de_cadena (char cadena[]);
- void copiar_cadena (char cadena_fuente[], char cadena_destino[]);
- int copiar_cadena_con_chequeo_de_indice (char cadena_fuente[],
- char cadena_destino[], int numero_maximo_de_caracteres);
- void copiar_cadena_rapido (char cadena_fuente[], char cadena_destino[]);
- int copiar_cadena_rapido_con_chequeo_de_indice (char cadena_fuente[],
- char cadena_destino[], int numero_maximo_de_caracteres);
- void aniadir_cadena (char cadena_fuente[], char cadena_destino[]);
- int insertar_cadena_con_chequeo_de_indice (char cadena_fuente[],
- char cadena_destino[], int indice_de_comienzo, int numero_maximo_de_caracteres);
- int insertar_cadena (char cadena_fuente[], char cadena_destino[],
- int indice_de_comienzo);
- void cadena_a_mayuscula (char cadena[]);
- void cadena_a_minuscula (char cadena[]);
- void invertir_cadena_rapido (char cadena[]);
- int invertir_cadena (char cadena[]);
- void intercambiar_cadenas_rapido (char cadena1[], char cadena2[]);
- int intercambiar_cadenas (char cadena1[], char cadena2[],
- int tamanio1, int tamanio2);
- int rellenar_cadena_rapido (char cadena[], int numero_de_blancos);
- int rellenar_cadena (char cadena[], int numero_de_blancos,
- int numero_maximo_de_caracteres);
- int contar_caracter_en_cadena (char cadena[], char caracter);
- int quitar_caracter_de_cadena (char cadena[], char caracter);
- int indice_de_caracter_en_cadena (char cadena[], char caracter);
- int indice_de_caracter_mas_a_la_derecha_en_cadena (char cadena[], char caracter);
- void reemplazar_caracter_en_cadena (char cadena[], char caracter_fuente,
- char caracter_destino);
- int llenar_cadena (char cadena[], int letra, int contador,
- int numero_maximo_de_caracteres);
- int primer_caracter_no_blanco_en_cadena (char cadena[]);
- int ultimo_caracter_no_blanco_en_cadena (char cadena[]);
- int cadenas_iguales (char cadena1[], char cadena2[], int ignorar_caso);
- int primera_diferencia_de_cadenas (char cadena1[], char cadena2[],
- int ignorar_caso);
- int comparar_cadenas (char cadena1[], char cadena2[], int ignorar_caso);
- int indice_subcadena_en_cadena (char subcadena[], char cadena[]);
- int contador_de_subcadenas_en_cadena (char subcadena[], char cadena[]);
- int quitar_subcadena_de_cadena (char subcadena[], char cadena[]);
- int indice_proxima_ocurrencia_de_subcadena_en_cadena (char subcadena[],
- char cadena[], int indice);
- int indice_patron_en_cadena (char subcadena[], char cadena[]);
-
- /* Definición de funciones: */
-
- /*
- Función principal.
- */
-
- void main (void)
- {
- #define ESC 27
- #define CARACTER_A_MAYUSCULA(c) ((c) >= 'a' && (c) <= 'z' ? ((c) & ~32) : (c))
- #define ENTRE(x,x1,x2) ((x) >= (x1) && (x) <= (x2))
-
- #define escribir_titulo(s) printf ("FUNCION:\n\n%s\n", s)
- #define leer_cadena1() { printf ("\ncadena1 (35 caracteres máximo): "); \
- scanf ("%35s", cadena1); }
- #define leer_cadena2() { printf ("\ncadena2 (35 caracteres máximo): "); \
- scanf ("%35s", cadena2); }
- #define leer_numero_maximo_de_caracteres() { printf ("\nnumero_maximo_de_caracteres: "); \
- scanf ("%d", &numero_maximo_de_caracteres); }
- #define leer_valor_entero(nombre_variable, variable) { printf ("\n%s: ", nombre_variable); \
- scanf ("%d", &variable); }
- #define leer_caracter1() { printf ("\ncaracter1: "); caracter1 = getche (); putch ('\n'); }
- #define leer_caracter2() { printf ("\ncaracter2: "); caracter2 = getche (); putch ('\n'); }
- #define escribir_cadena1() printf ("\ncadena1: %-35s\n", cadena1);
- #define escribir_cadena2() printf ("\ncadena2: %-35s\n", cadena2);
- #define escribir_valor_devuelto() printf ("\nvalor_devuelto: %d\n", valor_devuelto);
- #define escribir_entrada() printf ("\n\nVALORES DE ENTRADA:\n");
- #define escribir_salida() printf ("\n\nVALORES DE SALIDA:\n");
-
- char ch1, ch2;
- register int i;
- int numero_de_letras, numero_de_cifras;
- char cadena1[35+1], cadena2[35+1]; /* +1 para guardar el nulo */
- int numero_maximo_de_caracteres, valor_devuelto;
- char caracter1, caracter2;
- char *funciones[] =
- {
- "longitud_de_cadena",
- "copiar_cadena",
- "copiar_cadena_con_chequeo_de_indice",
- "copiar_cadena_rapido",
- "copiar_cadena_rapido_con_chequeo_de_indice",
- "aniadir_cadena",
- "insertar_cadena_con_chequeo_de_indice",
- "insertar_cadena",
- "cadena_a_mayuscula",
- "cadena_a_minuscula",
- "invertir_cadena_rapido",
- "invertir_cadena",
- "intercambiar_cadenas_rapido",
- "intercambiar_cadenas",
- "rellenar_cadena_rapido",
- "rellenar_cadena",
- "contar_caracter_en_cadena",
- "quitar_caracter_de_cadena",
- "indice_de_caracter_en_cadena",
- "indice_de_caracter_mas_a_la_derecha_en_cadena",
- "reemplazar_caracter_en_cadena",
- "llenar_cadena",
- "primer_caracter_no_blanco_en_cadena",
- "ultimo_caracter_no_blanco_en_cadena",
- "cadenas_iguales",
- "primera_diferencia_de_cadenas",
- "comparar_cadenas",
- "indice_subcadena_en_cadena",
- "contador_de_subcadenas_en_cadena",
- "quitar_subcadena_de_cadena",
- "indice_proxima_ocurrencia_de_subcadena_en_cadena",
- "indice_patron_en_cadena",
- NULL
- };
-
- do
- {
- borrar_pantalla ();
-
- printf ("FUNCIONES PARA PROBAR:\n\n");
- for (i = 0; funciones[i] != NULL; i++)
- {
- printf ("%c.- %-35.35s", 'A' + i > 'Z' ? '0' + i - ('Z' - 'A' + 1) :
- 'A' + i, funciones[i]);
- if (funciones[i+1] != NULL)
- {
- i++;
- printf (" %c.- %-35.35s\n", 'A' + i > 'Z' ? '0' + i - ('Z' - 'A' + 1) :
- 'A' + i, funciones[i]);
- }
- else
- printf ("\n");
- }
-
- numero_de_letras = i;
- numero_de_cifras = numero_de_letras > 'Z' - 'A' + 1 ? i - ('Z' - 'A' + 1) : 0;
- printf ("\nTecla letra correspondiente a función a probar (ESC para salir): ");
-
- do
- {
- ch1 = getch (); /* lee carácter correspondiente a opción */
- ch1 = CARACTER_A_MAYUSCULA (ch1); /* convierte carácter a mayúscula */
- } while (ch1 != ESC && ! ENTRE (ch1, 'A', 'A' + numero_de_letras - 1) &&
- (numero_de_cifras >= 0 && ! ENTRE (ch1, '0', '0' + numero_de_cifras - 1)));
-
- if (ch1 != ESC)
- do
- {
- borrar_pantalla ();
-
- switch (ch1)
- {
- case 'A':
- escribir_titulo ("int longitud_de_cadena (char cadena[]);");
- escribir_entrada ();
- leer_cadena1 ();
- valor_devuelto = longitud_de_cadena (cadena1);
- escribir_salida ();
- escribir_valor_devuelto ();
- break;
-
- case 'B':
- escribir_titulo ("void copiar_cadena (char cadena_fuente[], char cadena_destino[]);");
- escribir_entrada ();
- leer_cadena1 ();
- copiar_cadena (cadena1, cadena2);
- escribir_salida ();
- escribir_cadena2 ();
- break;
-
- case 'C':
- escribir_titulo ("int copiar_cadena_con_chequeo_de_indice (char cadena_fuente[],\n"
- "\t\tchar cadena_destino[], int numero_maximo_de_caracteres);");
- escribir_entrada ();
- leer_cadena1 ();
- leer_numero_maximo_de_caracteres ();
- valor_devuelto = copiar_cadena_con_chequeo_de_indice (cadena1,
- cadena2, numero_maximo_de_caracteres);
- escribir_salida ();
- escribir_cadena2 ();
- escribir_valor_devuelto ();
- break;
-
- case 'D':
- escribir_titulo ("void copiar_cadena_rapido (char cadena_fuente[], char cadena_destino[]);");
- escribir_entrada ();
- leer_cadena1 ();
- copiar_cadena (cadena1, cadena2);
- escribir_salida ();
- escribir_cadena2 ();
- break;
-
- case 'E':
- escribir_titulo ("int copiar_cadena_rapido_con_chequeo_de_indice (char cadena_fuente[],\n"
- "\t\tchar cadena_destino[], int numero_maximo_de_caracteres);");
- escribir_entrada ();
- leer_cadena1 ();
- leer_numero_maximo_de_caracteres ();
- valor_devuelto = copiar_cadena_con_chequeo_de_indice (cadena1,
- cadena2, numero_maximo_de_caracteres);
- escribir_salida ();
- escribir_cadena2 ();
- escribir_valor_devuelto ();
- break;
-
- case 'F':
- escribir_titulo ("void aniadir_cadena (char cadena_fuente[], char cadena_destino[]);");
- escribir_entrada ();
- leer_cadena1 ();
- leer_cadena2 ();
- aniadir_cadena (cadena1, cadena2);
- escribir_salida ();
- escribir_cadena2 ();
- break;
-
- case 'G':
- {
- int indice_de_comienzo;
- escribir_titulo ("int insertar_cadena_con_chequeo_de_indice (char cadena_fuente[], char\n"
- " cadena_destino[], int indice_de_comienzo, int numero_maximo_de_caracteres);");
- escribir_entrada ();
- leer_cadena1 ();
- leer_cadena2 ();
- leer_valor_entero ("indice_de_comienzo", indice_de_comienzo);
- leer_numero_maximo_de_caracteres ();
- valor_devuelto = insertar_cadena_con_chequeo_de_indice (cadena1, cadena2,
- indice_de_comienzo, numero_maximo_de_caracteres);
- escribir_salida ();
- escribir_cadena2 ();
- escribir_valor_devuelto ();
- }
- break;
-
- case 'H':
- {
- int indice_de_comienzo;
- escribir_titulo ("int insertar_cadena (char cadena_fuente[], char cadena_destino[],\n"
- " int indice_de_comienzo);");
- escribir_entrada ();
- leer_cadena1 ();
- leer_cadena2 ();
- leer_valor_entero ("indice_de_comienzo", indice_de_comienzo);
- valor_devuelto = insertar_cadena (cadena1, cadena2, indice_de_comienzo);
- escribir_salida ();
- escribir_cadena2 ();
- escribir_valor_devuelto ();
- }
- break;
-
- case 'I':
- escribir_titulo ("void cadena_a_mayuscula (char cadena[]);");
- escribir_entrada ();
- leer_cadena1 ();
- cadena_a_mayuscula (cadena1);
- escribir_salida ();
- escribir_cadena1 ();
- break;
-
- case 'J':
- escribir_titulo ("void cadena_a_minuscula (char cadena[]);");
- escribir_entrada ();
- leer_cadena1 ();
- cadena_a_minuscula (cadena1);
- escribir_salida ();
- escribir_cadena1 ();
- break;
-
- case 'K':
- escribir_titulo ("void invertir_cadena_rapido (char cadena[]);");
- escribir_entrada ();
- leer_cadena1 ();
- invertir_cadena_rapido (cadena1);
- escribir_salida ();
- escribir_cadena1 ();
- break;
-
- case 'L':
- escribir_titulo ("int invertir_cadena (char cadena[]);");
- escribir_entrada ();
- leer_cadena1 ();
- valor_devuelto = invertir_cadena (cadena1);
- escribir_salida ();
- escribir_cadena1 ();
- escribir_valor_devuelto ();
- break;
-
- case 'M':
- escribir_titulo ("void intercambiar_cadenas_rapido (char cadena1[], char cadena2[]);");
- escribir_entrada ();
- leer_cadena1 ();
- leer_cadena2 ();
- intercambiar_cadenas_rapido (cadena1, cadena2);
- escribir_salida ();
- escribir_cadena1 ();
- escribir_cadena2 ();
- break;
-
- case 'N':
- {
- int tamanio1, tamanio2;
- escribir_titulo ("int intercambiar_cadenas (char cadena1[], char cadena2[],\n"
- " int tamanio1, int tamanio2);");
- escribir_entrada ();
- leer_cadena1 ();
- leer_cadena2 ();
- leer_valor_entero ("tamanio1", tamanio1);
- leer_valor_entero ("tamanio2", tamanio2);
- valor_devuelto = intercambiar_cadenas (cadena1, cadena2,
- tamanio1, tamanio2);
- escribir_salida ();
- escribir_cadena1 ();
- escribir_cadena2 ();
- escribir_valor_devuelto ();
- }
- break;
-
- case 'O':
- {
- int numero_de_blancos;
- escribir_titulo ("int rellenar_cadena_rapido (char cadena[], int numero_de_blancos);");
- escribir_entrada ();
- leer_cadena1 ();
- leer_valor_entero ("numero_de_blancos", numero_de_blancos);
- valor_devuelto = rellenar_cadena_rapido (cadena1, numero_de_blancos);
- escribir_salida ();
- escribir_cadena1 ();
- escribir_valor_devuelto ();
- }
- break;
-
- case 'P':
- {
- int numero_de_blancos;
- escribir_titulo ("int rellenar_cadena (char cadena[], int numero_de_blancos,\n"
- " int numero_maximo_de_caracteres);");
- escribir_entrada ();
- leer_cadena1 ();
- leer_valor_entero ("numero_de_blancos", numero_de_blancos);
- valor_devuelto = rellenar_cadena (cadena1, numero_de_blancos,
- numero_maximo_de_caracteres);
- escribir_salida ();
- escribir_cadena1 ();
- escribir_valor_devuelto ();
- }
- break;
-
- case 'Q':
- escribir_titulo ("int contar_caracter_en_cadena (char cadena[], char caracter);");
- escribir_entrada ();
- leer_cadena1 ();
- leer_caracter1 ();
- valor_devuelto = contar_caracter_en_cadena (cadena1, caracter1);
- escribir_salida ();
- escribir_valor_devuelto ();
- break;
-
- case 'R':
- escribir_titulo ("int quitar_caracter_de_cadena (char cadena[], char caracter1);");
- escribir_entrada ();
- leer_cadena1 ();
- leer_caracter1 ();
- valor_devuelto = quitar_caracter_de_cadena (cadena1, caracter1);
- escribir_salida ();
- escribir_cadena1 ();
- escribir_valor_devuelto ();
- break;
-
- case 'S':
- escribir_titulo ("int indice_de_caracter_en_cadena (char cadena[], char caracter1);");
- escribir_entrada ();
- leer_cadena1 ();
- leer_caracter1 ();
- valor_devuelto = indice_de_caracter_en_cadena (cadena1, caracter1);
- escribir_salida ();
- escribir_valor_devuelto ();
- break;
-
- case 'T':
- escribir_titulo ("int indice_de_caracter_mas_a_la_derecha_en_cadena (char cadena[], char caracter1);");
- escribir_entrada ();
- leer_cadena1 ();
- leer_caracter1 ();
- valor_devuelto = indice_de_caracter_en_cadena (cadena1, caracter1);
- escribir_salida ();
- escribir_valor_devuelto ();
- break;
-
- case 'U':
- escribir_titulo ("void reemplazar_caracter_en_cadena (char cadena[], char caracter_fuente,\n"
- " char caracter_destino);");
- escribir_entrada ();
- leer_cadena1 ();
- leer_caracter1 ();
- leer_caracter2 ();
- reemplazar_caracter_en_cadena (cadena1, caracter1, caracter2);
- escribir_salida ();
- escribir_cadena1 ();
- break;
-
- case 'V':
- {
- int contador;
- escribir_titulo ("int llenar_cadena (char cadena[], int caracter, int contador,\n"
- " int numero_maximo_de_caracteres);");
- escribir_entrada ();
- leer_caracter1 ();
- leer_valor_entero ("contador", contador);
- leer_numero_maximo_de_caracteres ();
- valor_devuelto = llenar_cadena (cadena1, caracter1, contador,
- numero_maximo_de_caracteres);
- escribir_salida ();
- escribir_cadena1 ();
- escribir_valor_devuelto ();
- }
- break;
-
- case 'W':
- escribir_titulo ("int primer_caracter_no_blanco_en_cadena (char cadena[]);");
- escribir_entrada ();
- printf ("\ncadena 1: "); gets (cadena1); /* scanf no lee los primeros blancos */
- valor_devuelto = primer_caracter_no_blanco_en_cadena (cadena1);
- escribir_salida ();
- escribir_valor_devuelto ();
- break;
-
- case 'X': /* REVISAR */
- escribir_titulo ("int ultimo_caracter_no_blanco_en_cadena (char cadena[]);");
- escribir_entrada ();
- printf ("\ncadena 1: "); gets (cadena1); /* scanf no lee los últimos blancos */
- valor_devuelto = ultimo_caracter_no_blanco_en_cadena (cadena1);
- escribir_salida ();
- escribir_valor_devuelto ();
- break;
-
- case 'Y':
- {
- int ignorar_caso;
- escribir_titulo ("int cadenas_iguales (char cadena1[], char cadena2[], int ignorar_caso);");
- escribir_entrada ();
- leer_cadena1 ();
- leer_cadena2 ();
- leer_valor_entero ("ignorar_caso", ignorar_caso);
- valor_devuelto = cadenas_iguales (cadena1, cadena2, ignorar_caso);
- escribir_salida ();
- escribir_valor_devuelto ();
- }
- break;
-
- case 'Z':
- {
- int ignorar_caso;
- escribir_titulo ("int primera_diferencia_de_cadenas (char cadena1[], char cadena2[],\n"
- " int ignorar_caso);");
- escribir_entrada ();
- leer_cadena1 ();
- leer_cadena2 ();
- leer_valor_entero ("ignorar_caso", ignorar_caso);
- valor_devuelto = primera_diferencia_de_cadenas (cadena1, cadena2, ignorar_caso);
- escribir_salida ();
- escribir_valor_devuelto ();
- }
- break;
-
- case '0':
- {
- int ignorar_caso;
- escribir_titulo ("int comparar_cadenas (char cadena1[], char cadena2[], int ignorar_caso);");
- escribir_entrada ();
- leer_cadena1 ();
- leer_cadena2 ();
- leer_valor_entero ("ignorar_caso", ignorar_caso);
- valor_devuelto = comparar_cadenas (cadena1, cadena2, ignorar_caso);
- escribir_salida ();
- escribir_valor_devuelto ();
- }
- break;
-
- case '1':
- escribir_titulo ("int indice_subcadena_en_cadena (char subcadena[], char cadena[]);");
- escribir_entrada ();
- leer_cadena1 ();
- leer_cadena2 ();
- valor_devuelto = indice_subcadena_en_cadena (cadena1, cadena2);
- escribir_salida ();
- escribir_valor_devuelto ();
- break;
-
- case '2':
- escribir_titulo ("int contador_de_subcadenas_en_cadena (char subcadena[], char cadena[]);");
- escribir_entrada ();
- leer_cadena1 ();
- leer_cadena2 ();
- valor_devuelto = contador_de_subcadenas_en_cadena (cadena1, cadena2);
- escribir_salida ();
- escribir_valor_devuelto ();
- break;
-
- case '3':
- escribir_titulo ("int quitar_subcadena_de_cadena (char subcadena[], char cadena[]);");
- escribir_entrada ();
- leer_cadena1 ();
- leer_cadena2 ();
- valor_devuelto = quitar_subcadena_de_cadena (cadena1, cadena2);
- escribir_salida ();
- escribir_cadena1 ();
- escribir_valor_devuelto ();
- break;
-
- case '4':
- {
- int indice;
- escribir_titulo ("int indice_proxima_ocurrencia_de_subcadena_en_cadena (char subcadena[],\n"
- "\t\tchar cadena[], int indice);");
- escribir_entrada ();
- leer_cadena1 ();
- leer_cadena2 ();
- leer_valor_entero ("indice", indice);
- valor_devuelto = comparar_cadenas (cadena1, cadena2, indice);
- escribir_salida ();
- escribir_valor_devuelto ();
- }
- break;
-
- case '5':
- escribir_titulo ("int indice_patron_en_cadena (char subcadena[], char cadena[]);");
- escribir_entrada ();
- leer_cadena1 ();
- leer_cadena2 ();
- valor_devuelto = indice_patron_en_cadena (cadena1, cadena2);
- escribir_salida ();
- escribir_valor_devuelto ();
- break;
- }
-
- while (kbhit ()) /* vacía buffer de teclas */
- getch ();
-
- do
- {
- printf ("\n\n\n¿Deseas probar otra vez esta función (S/N)? ");
- ch2 = getch ();
- ch2 = CARACTER_A_MAYUSCULA (ch2);
- } while (ch2 != 'S' && ch2 != 'N');
-
- while (kbhit ()) /* vacía buffer de teclas */
- getch ();
-
- } while (ch2 == 'S');
-
- } while (ch1 != ESC);
- }
-
- /*
- Devuelve el número de caracteres in cadena
- */
-
- int longitud_de_cadena (char cadena[])
- {
- register int i;
-
- for (i = 0; cadena[i]; i++)
- ;
-
- return (i);
- }
-
- /*
- Copia el contenido de la cadena fuente a la cadena destino.
- No chequea índices. Esto quiere decir que si hacemos:
-
- void main (void)
- {
- cadena[2];
- copiar_cadena ("hola", cadena);
- }
-
- escribimos los caractes 'l' y 'a' en lugares de memoria desconocidos.
- */
-
- void copiar_cadena (char cadena_fuente[], char cadena_destino[])
- {
- register int i;
-
- for (i = 0; cadena_fuente[i] != '\0'; ++i)
- cadena_destino[i] = cadena_fuente[i];
-
- cadena_destino[i] = '\0';
- }
-
- /*
- Copia el contenido de la cadena fuente a la cadena destino.
-
- Devuelve 1 si cadena_destino no se ha podido copiar entera en cadena
- fuente; y 0 en caso contrario.
-
- Chequea índices. De esta forma podemos evitar errores desagradables
- como el ejemplo que se ha comentado en la función anterior.
-
- Ejemplo de utilización:
- estado = copiar_cadena_con_chequeo_de_indice ("cadena", variable_cadena,
- sizeof (variable_cadena));
- */
-
- int copiar_cadena_con_chequeo_de_indice (char cadena_fuente[],
- char cadena_destino[], int numero_maximo_de_caracteres)
- {
- register int i;
-
- numero_maximo_de_caracteres--;
-
- for (i = 0; cadena_fuente[i] != '\0' && i < numero_maximo_de_caracteres; i++)
- cadena_destino[i] = cadena_fuente[i];
-
- cadena_destino[i] = '\0';
-
- return (cadena_fuente[i] && i == numero_maximo_de_caracteres);
- }
-
- /*
- Copia el contenido de la cadena fuente a la cadena destino.
-
- Hace exactamente lo mismo que la función copiar_cadena() pero esta versión
- es mucho más rápida.
-
- Se han hecho dos optimizaciones:
-
- 1) El código:
-
- for (i = 0; cadena_fuente[i] != '\0'; ++i)
- cadena_destino[i] = cadena_fuente[i];
- cadena_destino[i] = '\0';
-
- es más eficiente así:
-
- for (i = 0; (cadena_destino[i] = cadena_fuente[i]) != '\0'; ++i)
- ;
-
- En la segunda versión, para cada testeo de la condición, se asigna un
- carácter de cadena_fuente a cadena_destino y después se comprueba si
- el carácter asignado es '\0', una vez que el carácter nulo ha sido
- asignado se termina el bucle.
-
- Todavía es más eficiente de la siguiente forma:
-
- for (i = 0; (cadena_destino[i] = cadena_fuente[i]); ++i)
- ;
-
- puesto que el carácter '\0' es equivalente al entero 0, y una expresión
- con valor 0 en C se considera falsa y una expresión con valor distinto de
- 0 se considera verdadera.
- */
-
- void copiar_cadena_rapido (char cadena_fuente[], char cadena_destino[])
- {
- register int i;
-
- for (i = 0; cadena_destino[i] = cadena_fuente[i]; i++)
- ;
- }
-
- /*
- Esta función hace lo mismo que la función copiar_cadena_con_chequeo_de_indice()
- pero con el código minimizado.
-
- La minimización se explica en el comentario de la función anterior.
- */
-
- int copiar_cadena_rapido_con_chequeo_de_indice (char cadena_fuente[],
- char cadena_destino[], int numero_maximo_de_caracteres)
- {
- register int i;
-
- numero_maximo_de_caracteres--;
-
- for (i = 0; (cadena_destino[i] = cadena_fuente[i]) &&
- i < numero_maximo_de_caracteres; i++)
- ;
-
- if (i == numero_maximo_de_caracteres && cadena_fuente[i])
- {
- cadena_destino[i] = '\0';
- return (1);
- }
- else
- return (0);
- }
-
- /*
- Añade el contenido de cadena_fuente a cadena_destino.
- No chequea índice.
- */
-
- void aniadir_cadena (char cadena_fuente[], char cadena_destino[])
- {
- register int i, j;
-
- for (i = 0; cadena_destino[i]; i++) /* encuentra el final de cadena_destino */
- ;
-
- for (j = 0; cadena_destino[i] = cadena_fuente[j]; i++, j++) /* añade cadena_fuente */
- ;
- }
-
- /*
- Inserta el contenido de cadena_destino en cadena_fuente a partir de
- indice_de_comienzo.
-
- Los valores devueltos son:
- -1: memoria insuficiente.
- 0: inserción con éxito.
- 1: inserción incompleta.
- */
-
- int insertar_cadena_con_chequeo_de_indice (char cadena_fuente[],
- char cadena_destino[], int indice_de_comienzo, int numero_maximo_de_caracteres)
- {
- register int i, j, longitud_cadena_fuente, longitud_cadena_destino;
-
- char *cadena_temporal;
-
- for (longitud_cadena_fuente = 0; cadena_fuente[longitud_cadena_fuente];
- ++longitud_cadena_fuente) /* obtiene longitud de cadena_fuente */
- ;
-
- for (longitud_cadena_destino = 0; cadena_fuente[longitud_cadena_destino];
- ++longitud_cadena_destino) /* obtiene longitud de cadena_destino */
- ;
-
- if (indice_de_comienzo > longitud_cadena_destino) /* añade */
- indice_de_comienzo = longitud_cadena_destino;
-
- if ((cadena_temporal = (char *) calloc (1, longitud_cadena_fuente +
- longitud_cadena_destino + 1)) == '\0')
- return (-1);
-
- for (i = 0; i < indice_de_comienzo; ++i)
- cadena_temporal[i] = cadena_destino[i];
-
- for (j = 0; cadena_temporal[i+j] = cadena_fuente[j]; j++)
- ;
-
- while (cadena_temporal[i+j] = cadena_destino[i])
- ++i;
-
- for (i = 0; (cadena_destino[i] = cadena_temporal[i]) &&
- i < numero_maximo_de_caracteres; i++)
- ;
-
- free (cadena_temporal);
-
- if (i == numero_maximo_de_caracteres && cadena_destino[i]) /* inserción está incompleta */
- {
- cadena_destino[i] = '\0';
- return (1);
- }
- else
- return (0);
- }
-
- /*
- Hace lo mismo que la función anterior pero no chequea índice. De esta forma
- es más rápida.
-
- Los valores devueltos son:
- -1: memoria insuficiente.
- 0: inserción con éxito.
- */
-
- int insertar_cadena (char cadena_fuente[], char cadena_destino[],
- int indice_de_comienzo)
- {
- register int i, j, longitud_cadena_fuente, longitud_cadena_destino;
-
- char *cadena_temporal;
-
- for (longitud_cadena_fuente = 0; cadena_fuente[longitud_cadena_fuente];
- ++longitud_cadena_fuente) /* obtiene longitud de cadena_fuente */
- ;
-
- for (longitud_cadena_destino = 0; cadena_fuente[longitud_cadena_destino];
- ++longitud_cadena_destino) /* obtiene longitud de cadena_destino */
- ;
-
- if (indice_de_comienzo > longitud_cadena_destino) /* añade */
- indice_de_comienzo = longitud_cadena_destino;
-
- if ((cadena_temporal = (char *) calloc (1, longitud_cadena_fuente +
- longitud_cadena_destino + 1)) == '\0')
- return (-1);
-
- for (i = 0; i < indice_de_comienzo; ++i)
- cadena_temporal[i] = cadena_destino[i];
-
- for (j = 0; cadena_temporal[i+j] = cadena_fuente[j]; j++)
- ;
-
- while (cadena_temporal[i+j] = cadena_destino[i])
- ++i;
-
- for (i = 0; cadena_destino[i] = cadena_temporal[i]; i++)
- ;
-
- free (cadena_temporal);
-
- return (0);
- }
-
- /*
- Convierte una cadena a caracteres en mayúsculas.
-
- Nota: los caracteres ASCII mayores de 127 como la ñ y las vocales acentuadas
- no son convertida a mayúsculas. Sería muy fácil contemplar estos caracteres
- también.
- */
-
- void cadena_a_mayuscula (char cadena[])
- {
- register int i;
-
- for (i = 0; cadena[i]; i++)
- if (cadena[i] >= 'a' && cadena[i] <= 'z')
- cadena[i] &= ~32;
- }
-
- /*
- Convierte una cadena a caracteres en minúsculas.
-
- Nota: los caracteres ASCII mayores de 127 como la ñ y las vocales acentuadas
- no son convertida a minúsculas. Sería muy fácil contemplar estos caracteres
- también.
- */
-
- void cadena_a_minuscula (char cadena[])
- {
- register int i;
-
- for (i = 0; cadena[i]; i++)
- if (cadena[i] >= 'A' && cadena[i] <= 'Z')
- cadena[i] |= 32;
- }
-
- /*
- Invierte el contenido de cadena.
-
- Este método requiere (1.5 * n) intercambios, siendo n el número de
- elementos del array.
- */
-
- void invertir_cadena_rapido (char cadena[])
- {
- char caracter_temporal;
-
- register int i, j;
-
- for (j = 0; cadena[j]; ++j) /* encuentra el final de cadena */
- ;
-
- for (i = 0, j--; i < j; i++, j--)
- {
- caracter_temporal = cadena[i];
- cadena[i] = cadena[j];
- cadena[j] = caracter_temporal;
- }
- }
-
- /*
- Invierte el contenido de cadena.
-
- Si ocurre un error en el proceso, esta función devuelve -1. En caso
- contrario devuelve 0.
-
- Este método requiere (2.0 * n) intercambios, siendo n el número de
- elementos del array.
-
- Dado una cadena de 512 caracteres, el primer método (función anterior)
- requiere 768 intercambios, mientras que el segundo método (esta función)
- requiere 1024 intercambios.
- */
-
- int invertir_cadena (char cadena[])
- {
- char *cadena_temporal;
-
- register int i, j;
-
- for (j = 0; cadena[j]; ++j) /* encuentra el final de cadena */
- ;
-
- if ((cadena_temporal = (char *) calloc (1, j)) == '\0')
- return (-1); /* no se pudo asignar memoria */
-
- for (i = 0, j--; j >= 0; i++, j--)
- cadena_temporal[i] = cadena[j];
-
- for (j = 0; j < i; j++)
- cadena[j] = cadena_temporal[j];
-
- free (cadena_temporal);
-
- return (0);
- }
-
- /*
- Intercambia el contenido de dos cadenas.
- */
-
- void intercambiar_cadenas_rapido (char cadena1[], char cadena2[])
- {
- register int i, j;
- char caracter_temporal;
-
- for (i = 0; cadena1[i] && cadena2[j]; i++)
- {
- caracter_temporal = cadena1[i];
- cadena1[i] = cadena2[i];
- cadena2[i] = caracter_temporal;
- }
-
- if (cadena1[i])
- {
- j = i;
- while (cadena1[i])
- cadena2[i] = cadena1[i++];
- cadena2[i] = '\0';
- cadena1[j] = '\0';
- }
- else
- {
- j = i;
- while (cadena2[i])
- cadena1[i] = cadena2[i++];
- cadena1[i] = '\0';
- cadena2[j] = '\0';
- }
- }
-
- /*
- Intercambia el contenido de dos cadenas.
- Los parámetros tamanio1 y tamanio2 representan los números máximos de
- caracteres en cadena1 y cadena2 respectivamente.
-
- Devuelve uno de los siguientes valores:
- 0: intercambio con éxito
- -1: memoria insuficiente
- 1: intercambio incompleto
- */
-
- int intercambiar_cadenas (char cadena1[], char cadena2[],
- int tamanio1, int tamanio2)
- {
- register int i, j;
- char caracter_temporal;
-
- for (i = 0; cadena1[i]; i++) /* obtiene la longitud de cadena1 */
- ;
-
- if (i >= tamanio2) /* ¿demasiado grande para cadena2? */
- return (1);
-
- for (i = 0; cadena2[i]; i++) /* obtiene la longitud de cadena2 */
- ;
-
- if (i >= tamanio1) /* ¿demasiado grande para cadena1? */
- return (1);
-
- for (i = 0; cadena1[i] && cadena2[i]; i++)
- {
- caracter_temporal = cadena1[i];
- cadena1[i] = cadena2[i];
- cadena2[i] = caracter_temporal;
- }
-
- if (cadena1[i])
- {
- j = i;
- while (cadena1[i])
- cadena2[i] = cadena1[i++];
- cadena2[i] = '\0';
- cadena1[j] = '\0';
- }
- else if (cadena2[i])
- {
- j = i;
- while (cadena2[i])
- cadena1[i] = cadena2[i++];
- cadena1[i] = '\0';
- cadena2[j] = '\0';
- }
-
- return (0);
- }
-
- /*
- Coloca el número de blancos especificado al comienzo de cadena.
-
- Devuelve el valor -1 si no existe memoria suficiente.
- */
-
- int rellenar_cadena_rapido (char cadena[], int numero_de_blancos)
- {
- register int i, j;
-
- char *cadena_temporal;
-
- for (i = 0; cadena[i]; i++) /* obtiene la longitud de cadena */
- ;
-
- if ((cadena_temporal = (char *) calloc (1, i + numero_de_blancos + 1)) == '\0')
- return (-1); /* no se puedo obtener memoria */
-
- for (i = 0; i < numero_de_blancos; i++)
- cadena_temporal[i] = ' ';
-
- for (j = 0; cadena_temporal[i] = cadena[j]; ++j, ++i)
- ;
-
- cadena_temporal[i] = '\0';
-
- for (i = 0; cadena[i] = cadena_temporal[i]; i++)
- ;
-
- free (cadena_temporal);
-
- return (0);
- }
-
- /*
- Coloca el número de blancos especificado al comienzo de cadena.
-
- Devuelve uno de los siguientes valores:
- -1: Memoria suficiente.
- 0: Exito.
- 1: Incompleto.
- */
-
- int rellenar_cadena (char cadena[], int numero_de_blancos,
- int numero_maximo_de_caracteres)
- {
- register int i, j;
-
- char *cadena_temporal;
-
- for (i = 0; cadena[i]; i++) /* obtiene la longitud de cadena */
- ;
-
- if (i + numero_de_blancos >= numero_maximo_de_caracteres)
- return (1);
- else if ((cadena_temporal = (char *) calloc (1, i + numero_de_blancos + 1)) == '\0')
- return (-1); /* no se puedo obtener memoria */
-
- for (i = 0; i < numero_de_blancos; i++)
- cadena_temporal[i] = ' ';
-
- for (j = 0; cadena_temporal[i] = cadena[j]; ++j, ++i)
- ;
-
- cadena_temporal[i] = '\0';
-
- for (i = 0; cadena[i] = cadena_temporal[i]; i++)
- ;
-
- free (cadena_temporal);
-
- return (0);
- }
-
- /*
- Devuelve el número de ocurrencias del carácter especificado en cadena.
- */
-
- int contar_caracter_en_cadena (char cadena[], char caracter)
- {
- register int i, contador = 0;
-
- for (i = 0; cadena[i]; i++)
- if (cadena[i] == caracter)
- contador++;
-
- return (contador);
- }
-
- /*
- Quita todas las ocurrencias del carácter especificado en cadena.
-
- Devuelve el valor -1 si no hubo suficiente memoria para la operación
- de borrado, y 0 en otro caso.
- */
-
- int quitar_caracter_de_cadena (char cadena[], char caracter)
- {
- register int i, j;
-
- char *cadena_temporal;
-
- for (i = 0; cadena[i]; i++)
- ;
-
- if ((cadena_temporal = (char *) calloc (1, i)) == '\0')
- return (-1);
-
- for (i = 0, j = 0; cadena[i]; i++)
- if (cadena[i] != caracter)
- cadena_temporal[j++] = cadena[i];
-
- for (cadena_temporal[j] = '\0', i = 0; cadena[i] = cadena_temporal[i]; i++)
- ;
-
- free (cadena_temporal);
-
- return (0);
- }
-
- /*
- Devuelve el índice de cadena que contiene la primera ocurrencia del
- carácter especificado. Si el carácter no se encuentra, devuelve -1.
- */
-
- int indice_de_caracter_en_cadena (char cadena[], char caracter)
- {
- register int i, indice_caracter = -1;
-
- for (i = 0; cadena[i] && indice_caracter == -1; i++)
- if (cadena[i] == caracter)
- indice_caracter = i;
-
- return (indice_caracter); /* -1 si no se encontró */
- }
-
- /*
- Devuelve el índice que contiene la primera ocurrencia del carácter
- especificado más a la derecha en cadena. Si el carácter no se encuentra,
- devuelve -1.
- */
-
- int indice_de_caracter_mas_a_la_derecha_en_cadena (char cadena[], char caracter)
- {
- register int i, indice_caracter = -1;
-
- for (i = 0; cadena[i]; i++)
- if (cadena[i] == caracter)
- indice_caracter = i;
-
- return (indice_caracter); /* -1 si no se encontró */
- }
-
- /*
- Reemplaza todas las ocurrencias de caracter_fuente con caracter_destino
- dentro de cadena.
- */
-
- void reemplazar_caracter_en_cadena (char cadena[], char caracter_fuente,
- char caracter_destino)
- {
- register int i;
-
- if (caracter_fuente != caracter_destino)
- for (i = 0; cadena[i]; i++)
- if (cadena[i] == caracter_fuente)
- cadena[i] = caracter_destino;
- }
-
- /*
- Coloca un número especificado de ocurrencias de un caracter dado en cadena.
- Devuelve 1 si el llenado no tuvo éxito o 0 en caso contrario.
- */
-
- int llenar_cadena (char cadena[], int caracter, int contador,
- int numero_maximo_de_caracteres)
- {
- register int i;
-
- if (contador + 1 > numero_maximo_de_caracteres) /* +1 reserva espacio para nulo */
- return (1); /* memoria insuficiente */
-
- for (i = 0; i < contador; ++i) /* llena la cadena */
- cadena[i] = caracter;
-
- cadena[i] = '\0';
-
- return (0);
- }
-
- /*
- Devuelve el índice del primer carácter que no es espacio blanco (un blanco
- o un tabulador) en cadena. Si todos los caracteres en la cadena son blanco,
- entonces devuelve -1.
- */
-
- int primer_caracter_no_blanco_en_cadena (char cadena[])
- {
- register int i, indice_primer_caracter_no_blanco = -1;
-
- for (i = 0; cadena[i] && indice_primer_caracter_no_blanco == -1; ++i)
- if (cadena[i] != ' ' && cadena[i] != '\t')
- indice_primer_caracter_no_blanco = i;
-
- return (indice_primer_caracter_no_blanco); /* -1 si todos los espacios son blancos */
- }
-
- /*
- Devuelve el índice del último carácter que no es espacio blanco (un blanco
- o un tabulador) en cadena. Si todos los caracteres en la cadena son blanco,
- entonces devuelve -1.
- */
-
- int ultimo_caracter_no_blanco_en_cadena (char cadena[])
- {
- register int i, indice_ultimo_caracter_no_blanco = -1;
-
- for (i = 0; cadena[i]; ++i)
- if (cadena[i] != ' ' && cadena[i] != '\t')
- indice_ultimo_caracter_no_blanco = i;
-
- return (indice_ultimo_caracter_no_blanco); /* -1 si todos los espacios son blancos */
- }
-
- /*
- Devuelve 1 si las cadenas cadena1 y cadena2 son iguales, en cualquier otro
- caso devuelve 0. Soporta proceso sensitivo al caso.
- */
-
- int cadenas_iguales (char cadena1[], char cadena2[], int ignorar_caso)
- {
- register int i;
- char caracter1, caracter2;
-
- for (i = 0; cadena1[i] && cadena2[i]; i++)
- if (cadena1[i] != cadena2[i])
- if (ignorar_caso)
- {
- caracter1 = cadena1[i] >= 'a' && cadena1[i] <= 'z' ?
- cadena1[i] & ~32 : cadena1[i];
- caracter2 = cadena2[i] >= 'a' && cadena2[i] <= 'z' ?
- cadena2[i] & ~32 : cadena2[i];
- if (caracter1 != caracter2)
- break;
- }
- else
- break;
-
- if (cadena1[i] || cadena2[i])
- return (0);
- else
- return (1);
- }
-
- /*
- Devuelve el índice de la primera diferencia entre dos cadenas o el valor -1
- si las dos cadenas son iguales.
- */
-
- int primera_diferencia_de_cadenas (char cadena1[], char cadena2[],
- int ignorar_caso)
- {
- register int i;
- char caracter1, caracter2;
-
- for (i = 0; cadena1[i] && cadena2[i]; i++)
- if (cadena1[i] != cadena2[i])
- if (ignorar_caso)
- {
- caracter1 = cadena1[i] >= 'a' && cadena1[i] <= 'z' ?
- cadena1[i] & ~32 : cadena1[i];
- caracter2 = cadena2[i] >= 'a' && cadena2[i] <= 'z' ?
- cadena2[i] & ~32 : cadena2[i];
- if (caracter1 != caracter2)
- break;
- }
- else
- break;
-
- if (cadena1[i] || cadena2[i])
- return (i);
- else
- return (-1);
- }
-
- /*
- Compara las cadenas especificadas. Devuelve 1 si cadena1 > cadena2,
- 2 si cadena2 > cadena1 y 0 si las cadenas son iguales. Soporta proceso
- sensitivo al caso.
- */
-
- int comparar_cadenas (char cadena1[], char cadena2[], int ignorar_caso)
- {
- register int i;
- char caracter1, caracter2;
- int resultado = 0; /* 0 igual, 1 cadena1 mayor, 2 cadena2 mayor */
-
- for (i = 0; cadena1[i] && cadena2[i]; i++)
- if (cadena1[i] != cadena2[i])
- {
- if (ignorar_caso)
- {
- caracter1 = cadena1[i] >= 'a' && cadena1[i] <= 'z' ?
- cadena1[i] & ~32 : cadena1[i];
- caracter2 = cadena2[i] >= 'a' && cadena2[i] <= 'z' ?
- cadena2[i] & ~32 : cadena2[i];
- if (caracter1 != caracter2)
- {
- if (caracter1 > caracter2)
- resultado = 1;
- else
- resultado = 2;
- break;
- }
- }
- else
- {
- if (cadena1[i] > cadena2[i])
- resultado = 1;
- else
- resultado = 2;
- break;
- }
- }
-
- if (resultado == 0)
- {
- if (cadena1[i] == cadena2[i])
- resultado = 0;
- else if (cadena1[i])
- resultado = 1;
- else
- resultado = 2;
- }
-
- return (resultado);
- }
-
- /*
- Devuelve el índice de comienzo de subcadena dentro de cadena o el valor -1
- si subcadena no se encuentra en cadena.
- */
-
- int indice_subcadena_en_cadena (char subcadena[], char cadena[])
- {
- register int i, j, k;
-
- for (i = 0; cadena[i]; i++)
- for (j = i, k = 0; cadena[j] == subcadena[k]; j++, k++)
- if (! subcadena[k+1]) /* fin de subcadena */
- return (i);
-
- return (-1); /* subcadena no encontrada */
- }
-
- /*
- Devuelve el número de ocurrencias de subcadena dentro de cadena.
- */
-
- int contador_de_subcadenas_en_cadena (char subcadena[], char cadena[])
- {
- register int i, j, k;
- int contador = 0;
-
- for (i = 0; cadena[i]; i++)
- for (j = i, k = 0; cadena[j] == subcadena[k]; j++, k++)
- if (! subcadena[k+1]) /* fin de subcadena */
- contador++;
-
- return (contador); /* 0 si subcadena no encontrada */
- }
-
- /*
- Quita la primera ocurrencia de subcadena dentro de cadena.
- Si tiene éxito, devuelve el valor 0. Si subcadena no es encontrada,
- devuelve el valor -1.
- */
-
- int quitar_subcadena_de_cadena (char subcadena[], char cadena[])
- {
- register int i, j, k;
- int indice_subcadena_en_cadena = -1;
-
- for (i = 0; cadena[i] && indice_subcadena_en_cadena == -1; i++)
- for (j = i, k = 0; cadena[j] == subcadena[k]; j++, k++)
- if (! subcadena[k+1]) /* fin de subcadena */
- indice_subcadena_en_cadena = i;
-
- if (indice_subcadena_en_cadena != -1)
- {
- for (k = 0; subcadena[k]; k++)
- ;
-
- for (j = indice_subcadena_en_cadena, i = indice_subcadena_en_cadena + k;
- cadena[i]; j++, i++)
- cadena[j] = cadena[i];
-
- cadena[j] = '\0';
-
- return (0);
- }
- else
- return (-1); /* subcadena no encontrada */
- }
-
- /*
- Devuelve el índice a la próxima ocurrencia de subcadena dentro de cadena
- comenzando en el índice especificado. Si subcadena no es encontrada, -1
- es devuelto.
- */
-
- int indice_proxima_ocurrencia_de_subcadena_en_cadena (char subcadena[],
- char cadena[], int indice)
- {
- register i, j, k;
-
- for (i = indice; cadena[i]; i++)
- for (j = i, k = 0; cadena[j] == subcadena[k]; j++, k++)
- if (! subcadena[k+1]) /* fin de subcadena */
- return (i);
-
- return (-1); /* subcadena no encontrada */
- }
-
- /*
- Devuelve el índice de comienzo de subcadena dentr de cadena. Si subcadena
- no es encontrada, devuelve -1.
-
- El array subcadena se puede considerar como un patrón, puesto que esta
- función permite que subcadena contenga el carácter comodín ? que es
- equivalente a cualquier carácter en las comparaciones.
- */
-
- int indice_patron_en_cadena (char subcadena[], char cadena[])
- {
- register int i, j, k;
-
- for (i = 0; cadena[i]; i++)
- for (j = i, k = 0; cadena[j] == subcadena[k] || subcadena[k] == '?'; j++, k++)
- if (! subcadena[k+1]) /* fin de subcadena */
- return (i);
-
- return (-1);
- }
- ende
- begine " VUELTA DEL CABALLO "
- /*
- Este programa realiza lo siguiente: Se da un tablero de nxn con n*n
- cuadros. Un caballo -que puede moverse según las reglas del ajedrez-
- se sitúa en el cuadro de coordenadas (x0,y0). Se pide encontrar, si
- existe, un recubrimiento del tablero completo, o sea, calcular un
- circuito de n*n-1 movimientos de forma que cada cuadro del tablero
- sea visitado exactamente una vez.
-
- La solución a este problema está basado en el método de tanteo
- sistemático (intento y error).
-
- La función más importante es ensayar() cuyo pseudocódigo es el siguiente:
-
- <PRINCIPIO ensayar>
- REPETIR seleccionar el nuevo candidato de la lista de futuros movimientos
- SI aceptable ENTONCES
- SI tablero no lleno ENTONCES
- LLAMAR ensayar nuevo movimiento
- SI no acertado ENTONCES
- borrar la anotación anterior
- FINSI
- FINSI
- FINSI
- HASTA movimiento acertado O no hay más posibilidades
- <FIN>
-
- Observaciones sobre el código:
-
- 1) Estudiar la función ensayar() a partir de este pseudocódigo.
-
- 2) El método utilizado para obtener el movimiento del caballo de (x1,y1)
- hasta (x2,y2) es sumar a (x1,y1) los vectores de diferencias.
-
- Los vectores de diferencia dif_x y dif_y contienen la diferencia de
- la coordenada x e y respectivamente desde la posición actual del
- caballo.
-
- Veáse con el siguiente tablero:
-
- 0 6 0 7 0
-
- 5 0 0 0 8
-
- 0 0 C 0 0
-
- 4 0 0 0 1
-
- 0 3 0 2 0
-
- C representa la posición del caballo; los números del 1 al 8 respre-
- sentan los 8 posibles movimientos. El primer movimiento se obtiene:
- x2 = x1 + 2; y2 = y1 + 1;
-
- 3) La macro tab() se utiliza para trabajar con los índices de 1 a n
- en la matriz del tablero en vez de con los índices reales 0 a n-1.
-
- 4) La condición «tablero no lleno» se expresa mediante «i < n*n» donde
- i es el número de movimiento del caballo actual y n la dimensión del
- tablero.
-
- 5) El significado de las asignaciones a los elementos de la matriz es:
-
- tab (x, y) = 0; /* el cuadro <x,y> no ha sido visitado */
- tab (x, y) = i; /* el cuador <x,y> ha sido visitado en el movimiento
- i-ésimo (1 ≤ i ≤ n*n) */
-
- NOTA: Con un dimensión de la matriz superior a 4, el proceso de encontrar
- la solución es muy lento. Por eso se ha puesto el límite en 8 aunque ya
- con este número el proceso es superlento (en términos de media, ya que
- puede dar la casualidad de que se encuentre la solución en los primeros
- intentos).
- */
-
- /* Ficheros a incluir: */
-
- #include <stdio.h> /* printf () */
- #include <conio.h> /* getch () */
- #include <stdlib.h> /* exit () */
-
- /* Macros: */
-
- #define NUM_MOVIMIENTOS_POSIBLES 8
- #define NMAXIMO 8
-
- #define BOOLEAN int
- #define TRUE 1
- #define FALSE 0
-
- #define ESC 27
-
- #define en(x,x1,x2) ((x) >= (x1) && (x) <= (x2))
-
- #define tab(i,j) tablero[(i)-1][(j)-1] /* tab(1,1) es en realidad tablero[0][0] */
-
- /* Variables globales: */
-
- int n, tablero[NMAXIMO][NMAXIMO];
- BOOLEAN movimiento_acertado;
- int dif_x [NUM_MOVIMIENTOS_POSIBLES] = { 2, 1, -1, -2, -2, -1, 1, 2 },
- dif_y [NUM_MOVIMIENTOS_POSIBLES] = { 1, 2, 2, 1, -1, -2, -2, -1 };
-
- /* Prototipos de las funciones: */
-
- void proceso (void);
- void ensayar (int i, int x, int y);
-
- /* Definiciones de las funciones: */
-
- void main (void)
- {
- do
- {
- printf ("\n\nVUELTA DEL CABALLO:\n ");
- proceso ();
- printf ("\nPulsa cualquier tecla para repetir o ESC para salir. ");
- } while (getch () != ESC);
- }
-
- void proceso (void)
- {
- register int i, j;
- int x0, y0;
-
- for (i = 1; i <= n; i++)
- for (j = 1; j <= n; j++)
- tab (i, j) = 0;
-
- printf ("\nIntroduce dimensión del tablero (1 ≤ n ≤ %d, n > 4 es muy lento): ", NMAXIMO);
- do
- {
- n = getch () - '0';
- } while (! en (n, 1, NMAXIMO));
- putch (n + '0');
-
- printf ("\nFila inicial (1 ≤ x ≤ %d): ", n);
- do
- {
- x0 = getch () - '0';
- } while (! en (x0, 1, n));
- putch (x0 + '0');
-
- printf ("\nColumna inicial (1 ≤ y ≤ %d): ", n);
- do
- {
- y0 = getch () - '0';
- } while (! en (y0, 1, n));
- putch (y0 + '0');
-
- tab (x0, y0) = 1;
- printf ("\n\n");
- ensayar (2, x0, y0);
-
- if (movimiento_acertado)
- for (printf ("\n\nLA SOLUCION ES:\n "), i = 1; i <= n; i++)
- {
- for (j = 1; j <= n; j++)
- printf ("%2d ", tab (i, j));
- printf ("\n ");
- }
- else
- printf ("\n\nNO HAY SOLUCION.\n");
- }
-
- void ensayar (int i, int x1, int y1)
- {
- int movimientos_realizados = 0;
- int x2, y2;
- const ncuadrado = n * n;
- static long unsigned num_movimientos_caballo = 0;
-
- do
- {
- movimiento_acertado = FALSE;
- x2 = x1 + dif_x[movimientos_realizados];
- y2 = y1 + dif_y[movimientos_realizados];
- movimientos_realizados++;
- if (kbhit ())
- if (getch () == ESC)
- exit (1);
- printf ("Número de movimientos del caballo (ESC para salir): %ld\r", ++num_movimientos_caballo);
- if (en (x2, 1, n) && en (y2, 1, n) && tab (x2, y2) == 0)
- {
- tab (x2, y2) = i;
- if (i < ncuadrado)
- {
- ensayar (i+1, x2, y2);
- if (! movimiento_acertado)
- tab (x2, y2) = 0;
- }
- else
- movimiento_acertado = TRUE;
- }
- } while (! movimiento_acertado &&
- movimientos_realizados != NUM_MOVIMIENTOS_POSIBLES);
- }
- ende
- begine " RELLENO DE UN TABLERO SEGUN UNAS REGLAS DADAS "
- /*
- Este programa es una variante del anterior (la vuelta del caballo). La
- idea es la misma, lo único que cambia es la forma de los movimientos:
- desde un determinado punto nos podemos mover tres cuadros (dejando dos
- en medio) en horizontal y vertical y dos cuadros (dejando uno en medio)
- en diagonal.
-
- Ejemplo:
-
- 1 9 12 4 17
- 20 23 15 7 22
- 11 5 18 10 13
- 2 8 21 3 16
- 19 24 14 6 25
-
- La única diferencia entre este programa y el anterior está en algunos
- nombres de mensajes y variables, y también en el contenido de los vectores
- dif_x y dif_y.
- */
-
- /* Ficheros a incluir: */
-
- #include <stdio.h> /* printf () */
- #include <conio.h> /* getch () */
- #include <stdlib.h> /* exit () */
-
- /* Macros: */
-
- #define NUM_MOVIMIENTOS_POSIBLES 8
- #define NMAXIMO 8
-
- #define BOOLEAN int
- #define TRUE 1
- #define FALSE 0
-
- #define ESC 27
-
- #define en(x,x1,x2) ((x) >= (x1) && (x) <= (x2))
-
- #define tab(i,j) tablero[(i)-1][(j)-1] /* tab(1,1) es en realidad tablero[0][0] */
-
- /* Variables globales: */
-
- int n, tablero[NMAXIMO][NMAXIMO];
- BOOLEAN movimiento_acertado;
- int dif_x [NUM_MOVIMIENTOS_POSIBLES] = { -3, -2, 0, 2, 3, 2, 0, -2 },
- dif_y [NUM_MOVIMIENTOS_POSIBLES] = { 0, -2, -3, -2, 0, 2, 3, 2 };
-
- /* Prototipos de las funciones: */
-
- void proceso (void);
- void ensayar (int i, int x, int y);
-
- /* Definiciones de las funciones: */
-
- void main (void)
- {
- do
- {
- printf ("\n\nRELLENO DE UN TABLERO SEGUN UNAS REGLAS DADAS:\n ");
- proceso ();
- printf ("\nPulsa cualquier tecla para repetir o ESC para salir. ");
- } while (getch () != ESC);
- }
-
- void proceso (void)
- {
- register int i, j;
- int x0, y0;
-
- for (i = 1; i <= n; i++)
- for (j = 1; j <= n; j++)
- tab (i, j) = 0;
-
- printf ("\nIntroduce dimensión del tablero (1 ≤ n ≤ %d, n > 4 es muy lento): ", NMAXIMO);
- do
- {
- n = getch () - '0';
- } while (! en (n, 1, NMAXIMO));
- putch (n + '0');
-
- printf ("\nFila inicial (1 ≤ x ≤ %d): ", n);
- do
- {
- x0 = getch () - '0';
- } while (! en (x0, 1, n));
- putch (x0 + '0');
-
- printf ("\nColumna inicial (1 ≤ y ≤ %d): ", n);
- do
- {
- y0 = getch () - '0';
- } while (! en (y0, 1, n));
- putch (y0 + '0');
-
- tab (x0, y0) = 1;
- printf ("\n\n");
- ensayar (2, x0, y0);
-
- if (movimiento_acertado)
- for (printf ("\n\nLA SOLUCION ES:\n "), i = 1; i <= n; i++)
- {
- for (j = 1; j <= n; j++)
- printf ("%2d ", tab (i, j));
- printf ("\n ");
- }
- else
- printf ("\n\nNO HAY SOLUCION.\n");
- }
-
- void ensayar (int i, int x1, int y1)
- {
- int movimientos_realizados = 0;
- int x2, y2;
- const ncuadrado = n * n;
- static long unsigned num_movimientos = 0;
-
- do
- {
- movimiento_acertado = FALSE;
- x2 = x1 + dif_x[movimientos_realizados];
- y2 = y1 + dif_y[movimientos_realizados];
- movimientos_realizados++;
- if (kbhit ())
- if (getch () == ESC)
- exit (1);
- printf ("Número de movimientos (ESC para salir): %ld\r", ++num_movimientos);
- if (en (x2, 1, n) && en (y2, 1, n) && tab (x2, y2) == 0)
- {
- tab (x2, y2) = i;
- if (i < ncuadrado)
- {
- ensayar (i+1, x2, y2);
- if (! movimiento_acertado)
- tab (x2, y2) = 0;
- }
- else
- movimiento_acertado = TRUE;
- }
- } while (! movimiento_acertado &&
- movimientos_realizados != NUM_MOVIMIENTOS_POSIBLES);
- }
- ende
- begine " PROBLEMA DE LAS OCHO REINAS "
- /*
- El problema de las ocho reinas consiste en situar ocho reinas en un
- tablero de ajedrez, de forma que ninguna reina pueda actuar sobre
- cualquiera de las otras.
-
- El programa es similar a los dos anteriores, el pseudocódigo de la
- función ensayar() es el siguiente:
-
- <PRINCIPIO ensayar> (i: entero)
- inicializar el conjunto de posiciones de la reina i-ésima
- REPETIR hacer la selección siguiente
- SI segura ENTONCES
- poner reina
- SI i < 8 ENTONCES
- LLAMAR ensayar (i + 1)
- SI no acertado ENTONCES
- quitar reina
- FINSI
- FINSI
- FINSI
- HASTA acertada O no hay más posiciones
- <FIN>
-
- Observaciones sobre el código:
-
- 1) Estudiar la función ensayar() a partir de este pseudocódigo.
-
- 2) Vectores utilizados:
-
- int posiciones_en_columna[8]; /* RANGO: 1..8 */
- BOOLEAN reina_en_fila[8]; /* RANGO: 1..8 */
- BOOLEAN reina_en_diagonal_normal[15]; /* RANGO: -7..7 */
- BOOLEAN reina_en_diagonal_inversa[15]; /* RANGO: 2..16 */
-
- En C, el primer elemento de cada vector tiene índice 0, esto es
- fácil solucionarlo con las siguientes macros:
-
- #define c(i) posiciones_en_columna[(i)-1]
- #define f(i) reina_en_fila[(i)-1]
- #define dn(i) reina_en_diagonal_normal[(i)+7]
- #define di(i) reina_en_diagonal_inversa[(i)-2]
-
- Significado de los vectores:
-
- c(i) : la posición de la reina en la columna i
- f(j) : indicativo de que no hay reina en la fila j-ésima
- dn(k): indicativo de que no hay reina en la diagonal normal (\) k-ésima
- di(k): indicativo de que no hay reina en la diagonal invertida (/) k-ésima
-
- Dado que se sabe, por las reglas del ajedrez, que una reina actúa
- sobre todas las piezas situadas en la misma columna, fila o diagonal
- del tablero se deduce que cada columna puede contener una y sólo una
- reina, y que la elección de la situación de la reina i-ésima puede
- restringirse a los cuadros de la columna i. Por tanto, el parámetro
- i se convierte en el índice de columna, y por ello el proceso de
- selección de posiciones queda limitado a los ocho posibles valores
- del índice de fila j.
-
- A partir de estos datos, la línea poner reina del pseudocódigo es:
-
- c (i) = j; f (j) = di (i + j) = dn (i - j) = FALSE;
-
- y la línea quitar reina del pseudocódigo:
-
- f (j) = di (i + j) = dn (i - j) = TRUE;
-
- y la condición segura del pseudocódigo:
-
- f (i) && di (i + j) && dn (i - j)
- */
-
- /* Ficheros a incluir: */
-
- #include <stdio.h> /* printf () */
- #include <conio.h> /* getch () */
-
- /* Macros: */
-
- #define BOOLEAN int
- #define TRUE 1
- #define FALSE 0
-
- /* Variables globales: */
-
- BOOLEAN acertado;
-
- int posiciones_en_columna[8];
- BOOLEAN reina_en_fila[8];
- BOOLEAN reina_en_diagonal_normal[15];
- BOOLEAN reina_en_diagonal_inversa[15];
-
- #define c(i) posiciones_en_columna[(i)-1] /* rango de índice: 1..8 */
- #define f(i) reina_en_fila[(i)-1] /* rango de índice: 1..8 */
- #define dn(i) reina_en_diagonal_normal[(i)+7] /* rango de índice: -7..7 */
- #define di(i) reina_en_diagonal_inversa[(i)-2] /* rango de índice: 2..16 */
-
- /* Prototipos de las funciones: */
-
- void proceso (void);
- void ensayar (int i);
-
- /* Definiciones de las funciones: */
-
- void main (void)
- {
- printf ("\n\nPROBLEMA DE LAS OCHO REINAS:\n ");
- proceso ();
- printf ("\n\nPulsa cualquier tecla para finalizar. ");
- getch ();
- }
-
- void proceso (void)
- {
- register int i;
-
- for (i = 1; i <= 8; i++)
- f (i) = TRUE;
- for (i = 2; i <= 16; i++)
- di (i) = TRUE;
- for (i = -7; i <= 7; i++)
- dn (i) = TRUE;
-
- ensayar (1);
-
- if (acertado)
- for (printf ("\n\nLA SOLUCION ES:\n\n"), i = 1; i <= 8; i++)
- {
- for (j = 1; j <= 8; j++)
- printf ("%2d", c (j) == i ? 1 : 0);
- printf ("\n");
- }
- else
- printf ("\n\nNO HAY SOLUCION.\n");
- }
-
- void ensayar (int i)
- {
- int j = 0;
-
- do
- {
- j++;
- acertado = FALSE;
- if (f (j) && di (i + j) && dn (i - j))
- {
- c (i) = j;
- f (j) = di (i + j) = dn (i - j) = FALSE;
- if (i < 8)
- {
- ensayar (i + 1);
- if (! acertado)
- f (j) = di (i + j) = dn (i - j) = TRUE;
- }
- else
- acertado = TRUE;
- }
- } while (! acertado && j != 8);
- }
- ende
- begine " PROBLEMA DE LAS OCHO REINAS AMPLIADO "
- /*
- Este programa es una ampliación del anterior. En el anterior encontrábamos
- una solución, en éste vamos encontrar e imprimir todas las soluciones.
-
- Para ello lo único que hay que hacer es modificar sensiblemente la
- función ensayar(). El nuevo pseudocódigo para esta función es:
-
- <PRINCIPIO ensayar> (i: entero)
- Entorno:
- j es una variable entera
- Lógica:
- PARA j <- 1 HASTA dimensión tablero CON INCREMENTO 1 HACER
- seleccionar el candidato j-ésimo
- SI aceptable ENTONCES
- anotarlo
- SI i < dimensión tablero ENTONCES
- LLAMAR ensayar (i + 1)
- SINO
- imprimir solución
- FINSI
- cancelar anotación
- FINSI
- FINPARA
- <FIN>
- */
-
- /* Ficheros a incluir: */
-
- #include <stdio.h> /* printf () */
- #include <conio.h> /* getch () */
- #include <stdlib.h> /* exit () */
-
- /* Macros: */
-
- #define BOOLEAN int
- #define TRUE 1
- #define FALSE 0
-
- #define ESC 27
-
- /* Variables globales: */
-
- int posiciones_en_columna[8];
- BOOLEAN reina_en_fila[8];
- BOOLEAN reina_en_diagonal_normal[15];
- BOOLEAN reina_en_diagonal_inversa[15];
-
- #define c(i) posiciones_en_columna[(i)-1] /* rango de índice: 1..8 */
- #define f(i) reina_en_fila[(i)-1] /* rango de índice: 1..8 */
- #define dn(i) reina_en_diagonal_normal[(i)+7] /* rango de índice: -7..7 */
- #define di(i) reina_en_diagonal_inversa[(i)-2] /* rango de índice: 2..16 */
-
- /* Prototipos de las funciones: */
-
- void proceso (void);
- void escribir_solucion (void);
- void ensayar (int i);
-
- /* Definiciones de las funciones: */
-
- void main (void)
- {
- printf ("\n\nENCONTRAR TODAS LAS SOLUCIONES DEL PROBLEMA DE LAS OCHO REINAS:\n ");
- proceso ();
- printf ("\n\nPulsa cualquier tecla para finalizar. ");
- getch ();
- }
-
- void proceso (void)
- {
- register int i;
-
- for (i = 1; i <= 8; i++)
- f (i) = TRUE;
- for (i = 2; i <= 16; i++)
- di (i) = TRUE;
- for (i = -7; i <= 7; i++)
- dn (i) = TRUE;
-
- printf ("\nPulsar ESC para salir o cualquier otra tecla para ver siguiente solución.\n");
- ensayar (1);
- }
-
- void escribir_solucion (void)
- {
- register int i, j;
- static numero_solucion = 0;
-
- printf ("\nSolución %d:\n", ++numero_solucion);
- for (i = 1; i <= 8; i++)
- {
- for (j = 1; j <= 8; j++)
- printf ("%2d", c (j) == i ? 1 : 0);
- printf ("\n");
- }
- if (getch () == ESC)
- exit (1);
- }
-
- void ensayar (int i)
- {
- register int j;
-
- for (j = 1; j <= 8; j++)
- if (f (j) && di (i + j) && dn (i - j))
- {
- c (i) = j;
- f (j) = di (i + j) = dn (i - j) = FALSE;
- if (i < 8)
- ensayar (i + 1);
- else
- escribir_solucion ();
- f (j) = di (i + j) = dn (i - j) = TRUE;
- }
- }
- ende
- end lección 6
-
- ; LECCION 7
- begin
- begine " 21 FUNCIONES DE MANIPULACION DE CADENAS DE CARACTERES "
- /*
- Este programa consta de 21 funciones sobre manipulación de punteros a cadenas
- de arrays y la función main para probar las funciones mencionadas.
-
- Hay dos cosas importantes que comentar:
-
- 1) En este ejemplo hablamos de strings en vez de cadenas de caracteres
- porque es la denominación más usada en C.
-
- 2) La lógica (la estructura) de este ejemplo es exactamente la misma que
- la del último ejemplo de la lección anterior. Ver el comentario al
- principio de dicho ejemplo si no se comprende algo de éste (como la
- compilación condicional #if __TURBOC__, la librería alloc.h, la
- estructura de la función main(), ...
- */
-
- /* Ficheros a incluir: */
-
- #include <stdio.h> /* printf (), puts (), scanf (), gets () */
- #include <alloc.h> /* calloc(), free () */
- #include <conio.h> /* clrscr () si TURBO C, putch (), getch () */
- #include <dos.h> /* int86 (), union REGS */
-
- /* Compilación condicional: */
-
- #ifdef __TURBOC__
- #define borrar_pantalla clrscr
- #else
- void borrar_pantalla (void) /* sólo hay que saber de esta función, en este momento, ... */
- { /* ... que borra la pantalla, no qué significa estas sentecias */
- union REGS regs;
- regs.h.ah = 6; /* código de desplazamiento de la pantalla */
- regs.h.al = 0; /* código de borrar la pantalla */
- regs.h.ch = 0; /* fila inicial */
- regs.h.cl = 0; /* columna inicial */
- regs.h.dh = 24; /* fila final */
- regs.h.dl = 79; /* columna final */
- regs.h.bh = 7; /* la línea de borrado en negra */
- int86 (0x10, ®s, ®s);
- regs.h.ah = 2; /* función de direccionamiento del cursor */
- regs.h.dl = 0; /* coordenada de la columna */
- regs.h.dh = 0; /* coordenada de la fila */
- regs.h.bh = 0; /* página de vídeo */
- int86 (0x10, ®s, ®s);
- }
- #endif
-
- /* Prototipos de funciones utilizadas: */
-
- int longitud_string (char *s);
- int longitud_string_version_2 (char *s);
- int longitud_string_version_3 (char *s);
- int indice_de_caracter_en_string (char *s, char caracter);
- int contador_de_caracter_en_string (char *s, char c);
- void reemplazar_caracter_en_string (char *s, char viejo_caracter,
- char nuevo_caracter);
- void string_a_mayuscula (char *s);
- void string_a_minuscula (char *s);
- void copiar_rapido_string (char *s1, char *s2);
- int copiar_string_con_chequeo_de_indie (char *s1, char *s2,
- int numero_maximo_de_caracteres);
- void copiar_string_recursivo (char *s1, char *s2);
- void aniadir_rapido_string (char *s1, char *s2);
- int strings_iguales (char *s1, char *s2, int ignorar_caso);
- int comparar_strings (char *s1, char *s2, int ignorar_caso);
- int primera_diferencia_entre_strings (char *s1, char *s2, int ignorar_caso);
- int indice_de_substring_en_string (char *substring, char *string);
- int contador_de_string (char *substring, char *string);
- int ascii_a_int (char *string, int *valor);
- void int_a_ascii (int valor, char *string);
- int comparar_strings_sin_ignorar_caso (char *s1, char *s2);
- char *salvar_string (char *s);
-
- /* Definición de funciones: */
-
- /*
- Función principal.
- */
-
- void main (void)
- {
- #define ESC 27
- #define CARACTER_A_MAYUSCULA(c) ((c) >= 'a' && (c) <= 'z' ? ((c) & ~32) : (c))
- #define ENTRE(x,x1,x2) ((x) >= (x1) && (x) <= (x2))
-
- #define leer_string(string,nombre_string) \
- { printf ("\n%s (35 caracteres máximo): ", nombre_string); \
- scanf ("%35s", string); }
- #define leer_s() leer_string(s,"s")
- #define leer_s1() leer_string(s1,"s1")
- #define leer_s2() leer_string(s2,"s2")
- #define leer_valor_entero(variable, nombre_variable) \
- { printf ("\n%s: ", nombre_variable); \
- scanf ("%d", &variable); }
- #define leer_caracter(caracter,nombre_caracter) \
- { printf ("\n%s: ", nombre_caracter); caracter = getche (); putch ('\n'); }
- #define leer_c() leer_caracter(c,"s")
- #define leer_c1() leer_caracter(c1,"s1")
- #define leer_c2() leer_caracter(c2,"s2")
-
- #define escribir_string(string,nombre_string) \
- printf ("\n%s: %-35s\n", nombre_string, string);
- #define escribir_s() escribir_string(s,"s")
- #define escribir_s1() escribir_string(s1,"s1")
- #define escribir_s2() escribir_string(s2, "s2")
- #define escribir_valor_devuelto() printf ("\nvalor_devuelto: %d\n", valor_devuelto);
- #define escribir_valor_entero(variable, nombre_variable) printf ("\n%s: %d\n", nombre_variable, variable);
- #define escribir_titulo(s) printf ("FUNCION:\n\n%s\n", s)
- #define escribir_entrada() printf ("\n\nVALORES DE ENTRADA:\n");
- #define escribir_salida() printf ("\n\nVALORES DE SALIDA:\n");
-
- char ch1, ch2;
- register int i;
- int numero_de_letras, numero_de_cifras;
- char s[35], s1[35], s2[35], c, c1, c2;
- int valor_devuelto;
-
- char *funciones[] =
- {
- "longitud_string",
- "longitud_string_version_2",
- "longitud_string_version_3",
- "indice_de_caracter_en_string",
- "contador_de_caracter_en_string",
- "reemplazar_caracter_en_string",
- "string_a_mayuscula",
- "string_a_minuscula",
- "copiar_rapido_string",
- "copiar_string_con_chequeo_de_indice",
- "copiar_string_recursivo",
- "aniadir_rapido_string",
- "strings_iguales",
- "comparar_strings",
- "comparar_strings_sin_ignorar_caso",
- "primera_diferencia_entre_strings",
- "indice_de_substring_en_string",
- "contador_de_string",
- "ascii_a_int",
- "int_a_ascii",
- "salvar_string",
- NULL
- };
-
- do
- {
- borrar_pantalla ();
-
- printf ("FUNCIONES PARA PROBAR:\n\n");
- for (i = 0; funciones[i] != NULL; i++)
- {
- printf ("%c.- %-35.35s", 'A' + i > 'Z' ? '0' + i - ('Z' - 'A' + 1) :
- 'A' + i, funciones[i]);
- if (funciones[i+1] != NULL)
- {
- i++;
- printf (" %c.- %-35.35s\n", 'A' + i > 'Z' ? '0' + i - ('Z' - 'A' + 1) :
- 'A' + i, funciones[i]);
- }
- else
- printf ("\n");
- }
-
- numero_de_letras = i;
- numero_de_cifras = numero_de_letras > 'Z' - 'A' + 1 ? i - ('Z' - 'A' + 1) : 0;
- printf ("\nTecla letra correspondiente a función a probar (ESC para salir): ");
-
- do
- {
- ch1 = getch (); /* lee carácter correspondiente a opción */
- ch1 = CARACTER_A_MAYUSCULA (ch1); /* convierte carácter a mayúscula */
- } while (ch1 != ESC && ! ENTRE (ch1, 'A', 'A' + numero_de_letras - 1) &&
- (numero_de_cifras >= 0 && ! ENTRE (ch1, '0', '0' + numero_de_cifras - 1)));
-
- if (ch1 != ESC)
- do
- {
- borrar_pantalla ();
-
- switch (ch1)
- {
- case 'A':
- escribir_titulo ("int longitud_string (char *s);");
- escribir_entrada ();
- leer_s ();
- valor_devuelto = longitud_string (s);
- escribir_salida ();
- escribir_valor_devuelto ();
- break;
-
- case 'B':
- escribir_titulo ("int longitud_string_version_2 (char *s);");
- escribir_entrada ();
- leer_s ();
- valor_devuelto = longitud_string_version_2 (s);
- escribir_salida ();
- escribir_valor_devuelto ();
- break;
-
- case 'C':
- escribir_titulo ("int longitud_string_version_3 (char *s);");
- escribir_entrada ();
- leer_s ();
- valor_devuelto = longitud_string_version_3 (s);
- escribir_salida ();
- escribir_valor_devuelto ();
- break;
-
- case 'D':
- escribir_titulo ("int indice_de_caracter_en_string (char *s, char c);");
- escribir_entrada ();
- leer_s ();
- leer_c ();
- valor_devuelto = indice_de_caracter_en_string (s, c);
- escribir_salida ();
- escribir_valor_devuelto ();
- break;
-
- case 'E':
- escribir_titulo ("int contador_de_caracter_en_string (char *s, char c);");
- escribir_entrada ();
- leer_s ();
- leer_c ();
- valor_devuelto = contador_de_caracter_en_string (s, c);
- escribir_salida ();
- escribir_valor_devuelto ();
- break;
-
- case 'F':
- escribir_titulo ("void reemplazar_caracter_en_string (char *s, char viejo_caracter,\n"
- " char nuevo_caracter);");
- escribir_entrada ();
- leer_s ();
- leer_caracter (c1, "viejo_caracter");
- leer_caracter (c2, "nuevo_caracter");
- reemplazar_caracter_en_string (s, c1, c2);
- escribir_salida ();
- escribir_s ();
- break;
-
- case 'G':
- escribir_titulo ("void string_a_mayuscula (char *s);");
- escribir_entrada ();
- leer_s ();
- string_a_mayuscula (s);
- escribir_salida ();
- escribir_s ();
- break;
-
- case 'H':
- escribir_titulo ("void string_a_minuscula (char *s);");
- escribir_entrada ();
- leer_s ();
- string_a_minuscula (s);
- escribir_salida ();
- escribir_s ();
- break;
-
- case 'I':
- escribir_titulo ("void copiar_rapido_string (char *s1, char *s2);");
- escribir_entrada ();
- leer_s1 ();
- copiar_rapido_string (s1, s2);
- escribir_salida ();
- escribir_s2 ();
- break;
-
- case 'J':
- {
- int numero_maximo_de_caracteres;
- escribir_titulo ("int copiar_string_con_chequeo_de_indice (char *s1, char *s2,\n"
- " int numero_maximo_de_caracteres);");
- escribir_entrada ();
- leer_s1 ();
- leer_valor_entero (numero_maximo_de_caracteres, "numero_maximo_de_caracteres");
- valor_devuelto = copiar_string_con_chequeo_de_indice (s1, s2, numero_maximo_de_caracteres);
- escribir_salida ();
- escribir_s2 ();
- escribir_valor_devuelto ();
- }
- break;
-
- case 'K':
- escribir_titulo ("void copiar_string_recursivo (char *s1, char *s2);");
- escribir_entrada ();
- leer_s1 ();
- copiar_rapido_string (s1, s2);
- escribir_salida ();
- escribir_s2 ();
- break;
-
- case 'L':
- escribir_titulo ("void aniadir_rapido_string (char *s1, char *s2);");
- escribir_entrada ();
- leer_string (s1, "string_fuente s1");
- leer_string (s2, "string_destino s2");
- aniadir_rapido_string (s1, s2);
- escribir_salida ();
- escribir_s2 ();
- break;
-
- case 'M':
- {
- int ignorar_caso;
- escribir_titulo ("int strings_iguales (char *s1, char *s2, int ignorar_caso);");
- escribir_entrada ();
- leer_s1 ();
- leer_s2 ();
- leer_valor_entero (ignorar_caso, "ignorar_caso");
- valor_devuelto = strings_iguales (s1, s2, ignorar_caso);
- escribir_salida ();
- escribir_valor_devuelto ();
- }
- break;
-
- case 'N':
- {
- int ignorar_caso;
- escribir_titulo ("int comparar_strings (char *s1, char *s2, int ignorar_caso);");
- escribir_entrada ();
- leer_s1 ();
- leer_s2 ();
- leer_valor_entero (ignorar_caso, "ignorar_caso");
- valor_devuelto = comparar_strings (s1, s2, ignorar_caso);
- escribir_salida ();
- escribir_valor_devuelto ();
- }
- break;
-
- case 'O':
- escribir_titulo ("int comparar_strings_sin_ignorar_caso (char *s1, char *s2);");
- escribir_entrada ();
- leer_s1 ();
- leer_s2 ();
- valor_devuelto = comparar_strings_sin_ignorar_caso (s1, s2);
- escribir_salida ();
- escribir_valor_devuelto ();
- break;
-
- case 'P':
- {
- int ignorar_caso;
- escribir_titulo ("int primera_diferencia_entre_strings (char *s1, char *s2, int ignorar_caso);");
- escribir_entrada ();
- leer_s1 ();
- leer_s2 ();
- leer_valor_entero (ignorar_caso, "ignorar_caso");
- valor_devuelto = primera_diferencia_entre_strings (s1, s2, ignorar_caso);
- escribir_salida ();
- escribir_valor_devuelto ();
- }
- break;
-
- case 'Q':
- escribir_titulo ("int indice_de_substring_en_string (char *substring, char *string);");
- escribir_entrada ();
- leer_string (s1, "substring");
- leer_string (s2, "string");
- valor_devuelto = indice_de_substring_en_string (s1, s2);
- escribir_salida ();
- escribir_valor_devuelto ();
- break;
-
- case 'R':
- escribir_titulo ("int contador_de_string (char *substring, char *string);");
- escribir_entrada ();
- leer_string (s1, "substring");
- leer_string (s2, "string");
- valor_devuelto = contador_de_string (s1, s2);
- escribir_salida ();
- escribir_valor_devuelto ();
- break;
-
- case 'S':
- {
- int valor;
- escribir_titulo ("int ascii_a_int (char *string, int *valor);");
- escribir_entrada ();
- leer_string (s, "string");
- valor_devuelto = ascii_a_int (s, &valor);
- escribir_salida ();
- escribir_valor_entero (valor, "valor");
- escribir_valor_devuelto ();
- }
- break;
-
- case 'T':
- {
- int valor;
- escribir_titulo ("void int_a_ascii (int valor, char *string);");
- escribir_entrada ();
- leer_valor_entero (valor, "valor");
- int_a_ascii (valor, s);
- escribir_salida ();
- escribir_string (s, "string");
- }
- break;
-
- case 'U':
- {
- char *string;
- escribir_titulo ("char *salvar_string (char *s);");
- escribir_entrada ();
- leer_s ();
- string = salvar_string (s);
- escribir_salida ();
- escribir_string (string, "valor devuelto");
- free (string);
- }
- break;
- }
-
- while (kbhit ()) /* vacía buffer de teclas */
- getch ();
-
- do
- {
- printf ("\n\n\n¿Deseas probar otra vez esta función (S/N)? ");
- ch2 = getch ();
- ch2 = CARACTER_A_MAYUSCULA (ch2);
- } while (ch2 != 'S' && ch2 != 'N');
-
- while (kbhit ()) /* vacía buffer de teclas */
- getch ();
-
- } while (ch2 == 'S');
-
- } while (ch1 != ESC);
- }
-
- /*
- Devuelve el número de caracteres en un string.
- */
-
- int longitud_string (char *s)
- {
- int longitud = 0;
-
- while (*s++)
- longitud++;
-
- return (longitud);
- }
-
- /*
- Devuelve la longitud del string s.
- Esta versión está basada en la sustracción de punteros.
- */
-
- int longitud_string_version_2 (char *s)
- {
- char *p = s;
-
- while (*p)
- p++;
-
- return (p - s);
- }
-
- /*
- Devuelve el número de caracteres del string s.
- Este cáculo lo hace de forma recursiva.
- */
-
- int longitud_string_version_3 (char *s)
- {
- return (*s ? 1 + longitud_string_version_3 (++s) : 0);
- }
-
- /*
- Devuelve el índice de la primera ocurrencia del carácter especificado
- en el string dado. Si dicho carácter no se encuentra en el string,
- entonces devuelve -1.
- */
-
- int indice_de_caracter_en_string (char *s, char c)
- {
- int contador, posicion = -1;
-
- for (contador = 0; *s && posicion == -1; contador++)
- if (*s++ == c)
- posicion = contador;
-
- return (posicion);
- }
-
- /*
- Devuelve el número de ocurrencias del carácter c en el string s.
- */
-
- int contador_de_caracter_en_string (char *s, char c)
- {
- int contador = 0;
-
- while (*s)
- if (*s++ == c)
- contador++;
-
- return (contador);
- }
-
- /*
- Reemplaza cada ocurrencia de viejo_caracter en el string s con el
- carácter contenido en nuevo_caracter.
- */
-
- void reemplazar_caracter_en_string (char *s, char viejo_caracter,
- char nuevo_caracter)
- {
- while (*s)
- if (*s == viejo_caracter)
- *s++ = nuevo_caracter;
- else
- s++;
- }
-
- /*
- Convierte un string a carácteres en mayúsculas.
- */
-
- void string_a_mayuscula (char *s)
- {
- while (*s)
- if (*s >= 'a' && *s <= 'z')
- *s++ &= ~32;
- else
- s++;
- }
-
- /*
- Convierte un string a carácteres en minúsculas.
- */
-
- void string_a_minuscula (char *s)
- {
- while (*s)
- if (*s >= 'A' && *s <= 'Z')
- *s++ |= 32;
- else
- s++;
- }
-
- /*
- Copia el contenido del string s1 en el string s2.
- No chequea índices.
- */
-
- void copiar_rapido_string (char *s1, char *s2)
- {
- while (*s2++ = *s1++)
- ;
- }
-
- /*
- Copia el string fuente s1 en el string destino s2.
- Se chequea índice devolviendo 1 si se intenta sobrepasar índice máximo o
- 0 si la copia ha sido completa.
- */
-
- int copiar_string_con_chequeo_de_indice (char *s1, char *s2,
- int numero_maximo_de_caracteres)
- {
- register int i;
-
- numero_maximo_de_caracteres--; /* deja espacio para nulo */
-
- for (i = 0; (*s2++ = *s1++) && (i < numero_maximo_de_caracteres); i++)
- ;
-
- if (i == numero_maximo_de_caracteres && *s1) /* ver si quedan caracteres en s1 */
- {
- *s2 = '\0';
- return (1);
- }
- else
- return (0);
- }
-
- /*
- Copia el contenido del string fuente s1 al string de destino s2.
- Esto lo hace de forma recursiva. No chequea índices.
- */
-
- void copiar_string_recursivo (char *s1, char *s2)
- {
- if (*s2 = *s1)
- copiar_string_recursivo (++s1, ++s2);
- }
-
- /*
- Añade el contenido del string fuente s1 al string destino s2.
- No chequea índices.
- */
-
- void aniadir_rapido_string (char *s1, char *s2)
- {
- while (*s2) /* encuentra el final de s2 */
- s2++;
-
- while (*s2++ = *s1++) /* lo añade */
- ;
- }
-
- /*
- Devuelve 1 si los strings s1 y s2 son iguales, en cualquier otro caso
- devuelve 0. Soporta proceso sensitivo al caso.
- */
-
- int strings_iguales (char *s1, char *s2, int ignorar_caso)
- {
- char c1, c2;
-
- for (; *s1 && *s2; s1++, s2++)
- if (*s1 != *s2)
- {
- if (ignorar_caso)
- {
- c1 = *s1 >= 'a' && *s1 <= 'z' ? *s1 & ~32 : *s1;
- c2 = *s2 >= 'a' && *s2 <= 'z' ? *s2 & ~32 : *s2;
- if (c1 != c2)
- break;
- }
- else
- break;
- }
-
- if (*s1 || *s2)
- return (0);
- else
- return (1);
- }
-
- /*
- Compara los strings especificados. Devuelve 1 si s1 > s2, 2 si s2 > s1
- y 0 si los strings son iguales. Suporta proceso sensitivo al caso.
- */
-
- int comparar_strings (char *s1, char *s2, int ignorar_caso)
- {
- char c1, c2;
- int resultado = 0; /* 0 igual, 1 s1 mayor, 2 s2 mayor */
-
- for (; *s1 && *s2; s1++, s2++)
- if (*s1 != *s2)
- {
- if (ignorar_caso)
- {
- c1 = *s1 >= 'a' && *s1 <= 'z' ? *s1 & ~32 : *s1;
- c2 = *s2 >= 'a' && *s2 <= 'z' ? *s2 & ~32 : *s2;
- if (c1 != c2)
- {
- if (c1 > c2)
- resultado = 1;
- else
- resultado = 2;
- break;
- }
- }
- else
- {
- if (*s1 > *s2)
- resultado = 1;
- else
- resultado = 2;
- break;
- }
- }
-
- if (resultado == 0)
- {
- if (*s1 == *s2)
- resultado = 0;
- else if (*s1)
- resultado = 1;
- else
- resultado = 2;
- }
-
- return (resultado);
- }
-
- /*
- Devuelve uno de los siguientes valores:
- < 1 si s1 es menor que s2
- == 0 si s1 y s2 son iguales
- > 1 si s1 es mayor que s2
-
- Tiene en cuenta el caso de los caracteres (por ejemplo: 'a' != 'A').
-
- Los valores distintos de 0 que se devuelven corresponden a la diferencia
- entre los primeros caracteres encontrados que son distintos.
- */
-
- int comparar_strings_sin_ignorar_caso (char *s1, char *s2)
- {
- while (*s1)
- if (*s1 - *s2)
- return (*s1 - *s2);
- else
- {
- s1++;
- s2++;
- }
-
- return ('\0'); /* iguales */
- }
-
- /*
- Devuelve la posición del índice del primer carácter que difiere entre
- s1 y s2. Si los strings son iguales, devuelve el valor -1.
- */
-
- int primera_diferencia_entre_strings (char *s1, char *s2, int ignorar_caso)
- {
- register int i;
- char c1, c2;
-
- for (i = 0; *s1 && *s2; s1++, s2++, i++)
- if (*s1 != *s2)
- {
- if (ignorar_caso)
- {
- c1 = *s1 >= 'a' && *s1 <= 'z' ? *s1 & ~32 : *s1;
- c2 = *s2 >= 'a' && *s2 <= 'z' ? *s2 & ~32 : *s2;
- if (c1 != c2)
- break;
- }
- }
-
- if (*s1 || *s2)
- return (1);
- else
- return (-1);
- }
-
- /*
- Devuelve el índice de comienzo de substring dentro de string o el valor -1
- si substring no se encuentra en string.
- */
-
- int indice_de_substring_en_string (char *substring, char *string)
- {
- char *substr, *str, *comienzo = string;
-
- while (*string)
- for (str = string++, substr = substring; *str == *substr; str++, substr++)
- if (! *(substr+1)) /* final de substr */
- return (string - comienzo - 1);
-
- return (-1); /* substr no encontrado */
- }
-
- /*
- Devuelve el número de ocurrencias de substring en string o el valor 0 si
- substring no se encuentra en string.
- */
-
- int contador_de_string (char *substring, char *string)
- {
- char *substr, *str;
-
- int contador = 0;
-
- while (*string)
- for (str = string++, substr = substring; *str == *substr; str++, substr++)
- if (! *(substr+1)) /* final de substr */
- ++contador;
-
- return (contador);
- }
-
- /*
- Convierte un string con caracteres que representan números a un valor
- numérico de tipo entero. Si el string contiene caracteres no válidos,
- se devuelve -1.
- */
-
- int ascii_a_int (char *string, int *valor)
- {
- int signo = 1; /* -1 si valor negativo */
-
- *valor = 0;
-
- while (*string == ' ') /* salta blancos */
- string++;
-
- if (*string == '-' || *string == '+')
- signo = (*string++ == '-') ? -1 : 1;
-
- while (*string)
- if ((*string >= '0') && (*string <= '9'))
- *valor = (*valor * 10) + (*string++ - 48); /* 48 es el código ascii de '0' */
- else
- return (-1); /* carácter no válido */
-
- *valor *= signo;
-
- return (0);
- }
-
- /*
- Convierte un valor entero a su representación string.
- */
-
- void int_a_ascii (int valor, char *string)
- {
- int signo = valor;
-
- char temporal, *str = string;
-
- if (valor < 0)
- valor *= -1;
-
- do
- {
- *string++ = (valor % 10) + 48; /* 48 es el código ascii de '0' */
- valor /= 10;
- } while (valor > 0);
-
- if (signo < 0)
- *string++ = '-';
-
- *string-- = '\0';
-
- while (str < string)
- {
- temporal = *string;
- *string-- = *str;
- *str++ = temporal;
- }
- }
-
- /*
- Devuelve una copia del string s.
- Si no se puede hacer la copia (no hay suficiente memoria) devuelve NULL.
- Esta memoria reservada tendrá que ser liberada posteriormente con la
- función free().
- */
-
- char *salvar_string (char *s)
- {
- char *str;
-
- if ((str = (char *) calloc (longitud_string (s) + 1, sizeof (char))) != NULL)
- copiar_rapido_string (s, str);
-
- return (str);
- }
- ende
- begine " ESCRITURA ALFABETICA DE NUMEROS "
- /*
- Programa que lee un número en dígitos decimales y los transforma en
- caracteres alfabéticos, es decir, en texto.
-
- El código está bastante documentado, así que no es difícil comprender
- la lógica seguida.
-
- Sólo hay una novedad en este programa: la inclusión de la librería <string.h>
- con la utilización de dos funciones de ellas: strcpy() y strcat(). En la
- librería <string.h> tenemos un montón de funciones relacionadas con strings.
- La mayoría de las funciones implementadas en el ejemplo anterior están en
- esta librería. La función strcpy() copia un string en otro y la función
- strcat() añade un string a otro. Ambas funciones las implementamos en el
- ejemplo anterior. El prototipo de estas dos funciones en el fichero string.h
- es:
-
- char *strcpy (char *destino, const char *fuente); /* devuelve destino */
- char *strcat (char *destino, const char *fuente); /* devuelve destino */
-
- Como curiosidad diré que este es el segundo programa que hice en C y con
- el que me adentré en el mundo de este lenguaje. Nunca lo he visto hecho en
- ningún sitio (ni ejecutable ni fuente).
- */
-
- /* Ficheros a incluir: */
-
- #include <stdio.h> /* printf () */
- #include <conio.h> /* getch (), putch (), cgets () */
- #include <string.h> /* strcpy (), strcat () */
-
- /* Macros: */
-
- #define IMPAR(x) ((x) % 2)
- #define CARACTER_A_MAYUSCULA(c) ((c) >= 'a' && (c) <= 'z' ? ((c) & ~32) : (c))
- #define ES_DIGITO(caracter) ((caracter) >= '0' && (caracter) <= '9')
-
- #define BOOLEAN int
- #define TRUE 1
- #define FALSE 0
-
- #define NUMMAXDIGITOS 36
- #define NUMMAXCARACTERES 500
-
- #define MASC 'M'
- #define FEM 'F'
-
- #define ESC 27
- #define ENTER 13
-
- /* Las siguientes constantes están definidas como macros para facilitar
- posibles cambios sobre ellas como convertirlas en minúsculas */
-
- #define PRESENTACION "PROGRAMA: ESCRITURA ALFABETICA DE NUMEROS"
- #define NADA "NO SE HA INTRODUCIDO NINGUN NUMERO"
- #define ERROR "NUMERO DEMASIADO LARGO"
- #define Y "Y "
- #define UNO "UNO "
- #define UN "UN "
- #define UNA "UNA "
- #define CERO "CERO"
- #define CIEN "CIEN "
- #define MIL "MIL "
- #define MILLON "UN MILLON "
- #define MILLONES "MILLONES "
- #define BILLON "UN BILLON "
- #define BILLONES "BILLONES "
- #define TRILLON "UN TRILLON "
- #define TRILLONES "TRILLONES "
- #define CUATRILLON "UN CUATRILLON "
- #define CUATRILLONES "CUATRILLONES "
- #define QUINTILLON "UN QUINTILLON "
- #define QUINTILLONES "QUINTILLONES "
-
- /* Tabla de los nombres de los 20 primeros números: */
-
- char *tabnom [] = { "", "", "DOS ", "TRES ", "CUATRO ", "CINCO ",
- "SEIS ", "SIETE ", "OCHO ", "NUEVE ", "DIEZ ", "ONCE ",
- "DOCE ", "TRECE ", "CATORCE ", "QUINCE ", "DIECISEIS ",
- "DIECISIETE ", "DIECIOCHO ", "DIECINUEVE ", "VEINTE "};
-
- /* Tabla de los nombres de las decenas: */
-
- char *tabdec [] = { "", "ANTONIO", "VEINTI", "TREINTA ", "CUARENTA ",
- "CINCUENTA ", "SESENTA ", "SETENTA ", "OCHENTA ", "NOVENTA " };
-
- /* Tabla de los nombres de las centenas masculinas: */
-
- char *tabcenmasc [] = { "", "CIENTO ", "DOSCIENTOS ", "TRESCIENTOS ",
- "CUATROCIENTOS ", "QUINIENTOS ", "SEISCIENTOS ", "SETECIENTOS ",
- "OCHOCIENTOS ", "NOVECIENTOS " };
-
- /* Tabla de los nombre de las centenas femeninas: */
-
- char *tabcenfem [] = { "", "CIENTO ", "DOSCIENTAS ", "TRESCIENTAS ",
- "CUATROCIENTAS ", "QUINIENTAS ", "SEISCIENTAS ", "SETECIENTAS ",
- "OCHOCIENTAS ", "NOVECIENTAS " };
-
- /* Declaración de las variables globales: */
-
- int tabnum [NUMMAXDIGITOS]; /* se almacena el número leído */
- char nomnum [NUMMAXCARACTERES]; /* número en caracteres alfábeticos */
- int numdigitos; /* número de dígitos del número leído */
-
- /* Declaración de las funciones utilizadas en el programa: */
-
- int leer_numero (void);
- char leer_genero (void);
- void obtener_nombre_de_numero (int *indice, char genero, int grupostrescifras);
- int numero (int ind, int ncifras);
- void nombre_de_numero_de_dos_cifras (int ind, char gener);
- void nombre_de_numero_de_tres_cifras (int *indic, char genero);
- void nombre_de_numero_de_seis_cifras (int *indic, char genero);
- void nombre_de_numero_de_x_cifras (int *indic, char gener, int numcifras,
- char *sustsingular, char *sustplural);
-
- /* Definición de funciones: */
-
- void main (void)
- {
- int grupostrescifras, indice, genero;
- BOOLEAN seguir = TRUE;
-
- while (seguir)
- {
- /* inicializar variables: */
- grupostrescifras = indice = numdigitos = 0;
-
- /* inicializar cadena: */
- strcpy (nomnum, "");
-
- /* presentar mensaje: */
- printf ("%s\n\r", PRESENTACION);
-
- /* obtener número y si éste es disntinto de cero también leer género: */
- if ((grupostrescifras = leer_numero ()) != 0 && numero (indice, 3) != 0)
- genero = leer_genero ();
-
- /* convertir número a texto: */
- obtener_nombre_de_numero (&indice, genero, grupostrescifras);
-
- /* escribir datos de salida: */
- printf ("\n\nNombre: %s", nomnum);
-
- /* preguntar si se desea seguir */
- printf ("\n\nPulsa ESC para terminar o cualquier otra tecla para seguir ");
- if (getch () == ESC)
- seguir = FALSE;
- else
- printf ("\r \r");
- }
- } /* main */
-
- int leer_numero (void)
- {
- char ch;
- int cociente, resto, incremento;
- register int i, j;
- char numero[NUMMAXDIGITOS+3], *p; /* +3: dos primeros elementos y último */
- BOOLEAN numero_correcto = FALSE;
-
- /* leer número */
- while (! numero_correcto)
- {
- printf ("\nIntroduce número: ");
- numero[0] = NUMMAXDIGITOS;
- cgets (numero);
- for (p = numero + 2, numdigitos = 0; *p && ES_DIGITO (*p); p++, numdigitos++)
- tabnum[numdigitos] = *p - '0';
- if (*p)
- printf ("\nNúmero incorrecto.\n");
- else
- numero_correcto = TRUE;
- }
-
- if (numdigitos == 0)
- return (0);
- else
- {
- /* quitar los ceros de la izquierda en la tabla de números */
- for (i = 0; i < numdigitos && tabnum[i] == 0; i++)
- ;
- if (i > 0)
- for (j = i; j < numdigitos; j++)
- tabnum [j-i] = tabnum [j];
-
- /* hallar cociente y resto para averiguar los ceros que hacen falta
- añadir a la izquierda y devolver el número de grupos de tres cifras */
- switch (numdigitos -= i)
- {
- case 0 :
- case 1 : cociente = 0;
- resto = 1;
- break;
- case 2 : cociente = 0;
- resto = 2;
- break;
- default: cociente = numdigitos / 3;
- resto = numdigitos % 3;
- }
-
- /* Se añaden los ceros a la izquierda necesarios para completar los grupos
- de tres cifras o sextetos. */
-
- /* a la variable numdigitos se le aumenta incremento que es el numero de
- ceros que hay que añadir a la izquierda cuyo valor depende del resto*/
- numdigitos += (incremento = resto == 0 ? 0 : resto == 1 ? 2 : 1);
- if (numdigitos != 3 && IMPAR (numdigitos))
- incremento += 3; /* completa sexteto (grupo de seis cifras) */
-
- /* introducir en la tabla de los números los ceros a la izquierda
- necesarios para completar el trío o sexteto */
- for (i = numdigitos - 1; i >= 0; i--)
- tabnum [i+incremento] = tabnum [i];
- for (i = 0; i < incremento; i++)
- tabnum [i] = 0;
-
- /* devolver el numero de grupos de tres cifras */
- return (resto != 0 ? cociente + 1 : cociente);
- }
- } /* leernumero */
-
- char leer_genero (void)
- {
- char ch;
-
- printf ("\n\nGénero (M o ENTER: masculino, F: femenino): ");
- do
- {
- ch = getch ();
- } while (CARACTER_A_MAYUSCULA (ch) != 'M' &&
- CARACTER_A_MAYUSCULA (ch) != 'F' && ch != ENTER);
-
- if (ch == ENTER)
- ch = 'M';
- else
- ch = CARACTER_A_MAYUSCULA (ch);
-
- return (putch (ch)); /* escribe carácter y lo devuelve */
- } /* leergenero */
-
- void obtener_nombre_de_numero (int *indice, char genero, int grupostrescifras)
- {
- switch (grupostrescifras)
- {
- case 0 :
- strcpy (nomnum, NADA);
- break;
- case 1 :
- if (*indice == 0 && numero (*indice, 3) ==0)
- strcpy (nomnum, CERO);
- else
- nombre_de_numero_de_tres_cifras (indice, genero);
- break;
- case 2 :
- nombre_de_numero_de_seis_cifras (indice, genero);
- break;
- case 3 :
- case 4 :
- nombre_de_numero_de_x_cifras (indice, genero, 12, MILLON, MILLONES);
- break;
- case 5 :
- case 6 :
- nombre_de_numero_de_x_cifras (indice, genero, 18, BILLON, BILLONES);
- break;
- case 7 :
- case 8 :
- nombre_de_numero_de_x_cifras (indice, genero, 24, TRILLON, TRILLONES);
- break;
- case 9 :
- case 10:
- nombre_de_numero_de_x_cifras (indice, genero, 30, CUATRILLON, CUATRILLONES);
- break;
- case 11:
- case 12:
- nombre_de_numero_de_x_cifras (indice, genero, 36, QUINTILLON, QUINTILLONES);
- break;
- default:
- strcpy (nomnum, ERROR);
- }
- } /* obtener_nombre_de_numero */
-
- /*
- Esta función convierte unas determinadas cifras de tabnum en un número.
- Concretamente convierte las cifras de tabnum que empiezan en el índice
- ind y terminan en ind+ncifras-1.
- */
-
- int numero (int ind, int ncifras)
- {
- register int i, num;
-
- for (i = num = 0; i < ncifras; i++)
- num = 10 * num + tabnum [ind + i];
-
- return (num);
- } /* numero */
-
- /*
- Esta función convierte un número de dos cifras en texto
- */
-
- void nombre_de_numero_de_dos_cifras (int ind, char gener)
- {
- /* asigna valor al elemento de índice 1 de la tabla tabnom */
- tabnom [1] = gener == FEM ? UNA : (numdigitos - ind <= 2 ? UNO : UN);
-
- /* si número a escribir es menor que 20, leemos nombre de tabnom */
- if (numero (ind, 2) <= 20)
- strcat (nomnum, tabnom [numero (ind, 2)]);
-
- /* número mayor que 20 */
- else
- {
- /* añadimos nombre de la decena */
- strcat (nomnum, tabdec [numero (ind, 1)]);
-
- /* si no es decena de veintena y no termina en 0, añadimos Y */
- if (numero (ind + 1, 1) != 0 && numero (ind, 1) != 2)
- strcat (nomnum, Y);
-
- /* añadimos nombre de la unidad */
- strcat (nomnum, tabnom [numero (ind + 1, 1)]);
- }
- } /* nombre_de_numero_de_dos_cifras */
-
- /*
- Esta función convierte un número de tres cifras en texto
- */
-
- void nombre_de_numero_de_tres_cifras (int *indic, char genero)
- {
- /* si número de tres cifras es 0, no se hace nada */
- if (numero (*indic, 3) == 0)
- ;
-
- /* si número de tres cifras en 100, se añade CIEN */
- else if (numero (*indic, 3) == 100)
- strcat (nomnum, CIEN);
-
- /* si no es ni 0 ni 100 */
- else
- {
- /* añadimos nombre de centena */
- strcat (nomnum, genero == MASC ?
- tabcenmasc [numero (*indic, 1)] : tabcenfem [numero (*indic, 1)]);
-
- /* añadimos nombre del grupo de dos cifras restantes */
- nombre_de_numero_de_dos_cifras (*indic + 1, genero);
- }
-
- /* aumentamos índice en 3 ya que hemos procesado tres cifras de tabnum */
- *indic += 3;
- } /* nombre_de_numero_de_tres_cifras */
-
- /*
- Esta función convierte un número de seis cifras en texto
- */
-
- void nombre_de_numero_de_seis_cifras (int *indic, char genero)
- {
- /* si primeras tres cifras en 0, se procesan las tres últimas cifras */
- if (numero (*indic, 3) == 0)
- *indic += 3;
-
- /* procesar tres primeras cifras del grupo de seis */
- else
- {
- /* si valor de tres primeras cifras es 1, no se escribe nada */
- if (numero (*indic, 3) == 1)
- *indic += 3;
-
- /* escribir nombre correspondiente a las tres primeras cifras */
- else
- nombre_de_numero_de_tres_cifras (indic, genero);
-
- /* añadir MIL al nombre de las tres primeras cifras si eran distintas de 1 */
- strcat (nomnum, MIL);
- }
-
- /* escribir nombre de grupo de tres cifras */
- nombre_de_numero_de_tres_cifras (indic, genero);
- } /* nombre_de_numero_de_seis_cifras */
-
- /*
- Esta función convierte un número de x cifras en texto.
- x es mayor de 6.
- */
-
- void nombre_de_numero_de_x_cifras (int *indic, char gener, int numcifras,
- char *sustsingular, char *sustplural)
- {
- /* si valor de número a escribir es 0, no se escribe nada */
- if (numero (*indic, numcifras) == 0)
- *indic += numcifras;
-
- /* si valor de número a escribir es distinto de 0 */
- else
- {
- /* si valor de las 6 primeras cifras es 0, no se escribe nada */
- if (numero (*indic, 6) == 0)
- *indic += 6;
-
- /* si valor de las 6 primeras cifras es 1, escribir sustantivo en
- singular; por ejemplo, si trabajamos con trillones, se escribe
- TRILLON no TRILLONES */
- else if (numero (*indic, 6) == 1)
- {
- *indic += 6;
- strcat (nomnum, sustsingular);
- }
-
- /* si valor de las 6 primeras cifras es distinto de 0, llama a
- función obtener_nombre_de_numero para que escriba las 6 primeras
- cifras, que han de escribirse en masculino puesto que el género
- sólo es aplicable a las últimas cifras del número; una vez escritas
- las 6 primeras cifras se le añade el sustantivo plural, por ejemplo
- si trabajamos con trillones, se añadiría TRILLONES */
- else
- {
- obtener_nombre_de_numero (indic, MASC, 2);
- strcat (nomnum, sustplural);
- }
-
- /* una vez escritas las 6 primeras cifras junto con el sustantivo
- correspondiente, se escriben el resto de las cifras llamando a
- la función obtener_nombre_de_numero */
- obtener_nombre_de_numero (indic, gener, (numcifras -= 6) / 3);
- }
- } /* nombre_de_numero_de_x_cifras */
- ende
- begine " ESCRITURA ALFABETICA DE NUMEROS VERSION 2 "
- /*
- Programa que lee un número en dígitos decimales y los transforma en
- caracteres alfabéticos, es decir, en texto. Este programa es una versión
- mejorada del programa del ejemplo anterior.
-
- Se han hecho dos mejoras importantes:
-
- 1) El programa del ejemplo anterior sólo aceptaba números enteros. Este
- programa acepta también números reales. La sintaxis de un número real
- correcta es la sintaxis de un número double en C. Esta sintaxis se
- describe unas líneas más abajo al explicar la función strtod().
-
- 2) En el programa anterior las palabras correspondientes al número en
- versión alfabética se partían en las líneas, lo cual no es muy estético.
- Esta versión permite escribir las palabras del nombre del número entre
- dos columnas especificadas y son partir las palabras entre líneas.
-
- El código está bastante documentado, así que no es difícil comprender
- la lógica seguida.
-
- Se han utilizado dos nuevas funciones con respecto al de la primera
- versión:
-
- 1) char *strchr (const char *s, int c);
-
- El protipo anterior se encuentra en el fichero string.h.
-
- Esta función devuelve un puntero a la primera ocurrencia del carácter
- c en s; si c no aparece en s, strchr devuelve NULL.
-
- 2) double strtod (const char *s, char **endptr);
-
- El prototipo anterior se encuentra en el fichero stdlib.h
-
- Esta función devuelve el valor de como un double, donde s es una
- secuencia de caracteres. El string debe tener el siguiente formato:
-
- [eb] [sn] [ddd] [.] [ddd] [fmt[sn]ddd]
- ══╗
- eb = espacio blanco ║
- sn = signo (+ o -) ║ Todos los elementos
- ddd = dígitos ╟─ entre [ ]
- fmt = e o E ║ son opcionales
- . = punto decimal ║
- ══╝
- El puntero endptr apunta, al terminar la función strtod, al último
- carácter válido: si el string tiene la sintaxis correcta de un número
- double, apuntará al carácter terminador nulo, en caso contrario apuntará
- al primer carácter de s que no coincida con la sintaxis de un double.
- */
-
- /* Ficheros a incluir: */
-
- #include <stdio.h> /* printf () */
- #include <conio.h> /* getch (), cgets () */
- #include <string.h> /* strcpy (), strcat (), strchr () */
- #include <stdlib.h> /* strtod () */
-
- /* Macros: */
-
- #define NUM(x) ((x) - '0')
- #define IMPAR(x) ((x) % 2)
- #define CARACTER_A_MAYUSCULA(c) ((c) >= 'a' && (c) <= 'z' ? ((c) & ~32) : (c))
- #define ES_DIGITO(caracter) ((caracter) >= '0' && (caracter) <= '9')
- #define ENTRE(x,x1,x2) ((x) >= (x1) && (x) <= (x2))
-
- #define BOOLEAN int
- #define TRUE 1
- #define FALSE 0
-
- #define NUMMAXDIGITOS 36
- #define NUMMAXCARACTERES 500
-
- #define MASC 'M'
- #define FEM 'F'
-
- #define ESC 27
- #define ENTER 13
- #define ESPACIO 32
-
- #define COLUMNA_MINIMA 2
- #define COLUMNA_MAXIMA 79
- #define DIFERENCIA_MINIMA_ENTRE_COLUMNAS 10
-
- /* Las siguientes constantes están definidas como macros para facilitar
- posibles cambios sobre ellas como convertirlas en minúsculas */
-
- #define PRESENTACION_VERSION_2 "PROGRAMA: ESCRITURA ALFABETICA DE NUMEROS"
- #define NADA "NO SE HA INTRODUCIDO NINGUN NUMERO"
- #define ERROR "NUMERO DEMASIADO LARGO"
- #define Y "Y "
- #define COMA "COMA "
- #define POTENCIA "POR DIEZ ELEVADO A "
- #define MAS "MAS "
- #define MENOS "MENOS "
- #define UNO "UNO "
- #define UN "UN "
- #define UNA "UNA "
- #define CERO "CERO "
- #define CIEN "CIEN "
- #define MIL "MIL "
- #define MILLON "UN MILLON "
- #define MILLONES "MILLONES "
- #define BILLON "UN BILLON "
- #define BILLONES "BILLONES "
- #define TRILLON "UN TRILLON "
- #define TRILLONES "TRILLONES "
- #define CUATRILLON "UN CUATRILLON "
- #define CUATRILLONES "CUATRILLONES "
- #define QUINTILLON "UN QUINTILLON "
- #define QUINTILLONES "QUINTILLONES "
-
- /* Tabla de los nombres de los 20 primeros números: */
-
- char *tabnom [] = { "", "", "DOS ", "TRES ", "CUATRO ", "CINCO ",
- "SEIS ", "SIETE ", "OCHO ", "NUEVE ", "DIEZ ", "ONCE ",
- "DOCE ", "TRECE ", "CATORCE ", "QUINCE ", "DIECISEIS ",
- "DIECISIETE ", "DIECIOCHO ", "DIECINUEVE ", "VEINTE "};
-
- /* Tabla de los nombres de las decenas: */
-
- char *tabdec [] = { "", "ANTONIO", "VEINTI", "TREINTA ", "CUARENTA ",
- "CINCUENTA ", "SESENTA ", "SETENTA ", "OCHENTA ", "NOVENTA " };
-
- /* Tabla de los nombres de las centenas masculinas: */
-
- char *tabcenmasc [] = { "", "CIENTO ", "DOSCIENTOS ", "TRESCIENTOS ",
- "CUATROCIENTOS ", "QUINIENTOS ", "SEISCIENTOS ", "SETECIENTOS ",
- "OCHOCIENTOS ", "NOVECIENTOS " };
-
- /* Tabla de los nombre de las centenas femeninas: */
-
- char *tabcenfem [] = { "", "CIENTO ", "DOSCIENTAS ", "TRESCIENTAS ",
- "CUATROCIENTAS ", "QUINIENTAS ", "SEISCIENTAS ", "SETECIENTAS ",
- "OCHOCIENTAS ", "NOVECIENTAS " };
-
- /* Declaración de las variables globales: */
-
- int tabnum [NUMMAXDIGITOS]; /* se almacena el número leído */
- char nomnum [NUMMAXCARACTERES]; /* número en caracteres alfábeticos */
- int numdigitos; /* número de dígitos del número leído */
-
- /* Declaración de las funciones utilizadas en el programa: */
-
- void leer_numero (char numero[]);
- char leer_genero (void);
- void leer_columnas (int *columna1, int *columna2);
- void obtener_numero (char *strnum, char gen);
- void obtener_num_sin_exp (char *s, char gen);
- void obtener_parte_entera_num (char *s, char gen);
- void obtener_nombre_de_numero (int *indice, char genero, int grupostrescifras);
- int numero (int ind, int ncifras);
- void nombre_de_numero_de_dos_cifras (int ind, char gener);
- void nombre_de_numero_de_tres_cifras (int *indic, char genero);
- void nombre_de_numero_de_seis_cifras (int *indic, char genero);
- void nombre_de_numero_de_x_cifras (int *indic, char gener, int numcifras,
- char *sustsingular, char *sustplural);
- void escribir (char *s, int c1, int c2);
-
- /* Definición de funciones: */
-
- void main (void)
- {
- char genero;
- BOOLEAN seguir = TRUE;
- char numero[NUMMAXDIGITOS+3];
- int c1, c2;
-
- while (seguir)
- {
- /* presentar mensaje: */
- printf ("%s\n\r", PRESENTACION_VERSION_2);
-
- /* leer número, género y columnas: */
- leer_numero (numero);
- genero = leer_genero ();
- leer_columnas (&c1, &c2);
-
- /* convertir número a texto: */
- obtener_numero (numero+2, genero);
-
- /* escribir datos de salida: */
- printf ("\nNombre correspondiente al número introducido:\n\n");
- escribir (nomnum, c1, c2);
-
- /* preguntar si se desea seguir */
- printf ("\n\nPulsa ESC para terminar o cualquier otra tecla para seguir ");
- if (getch () == ESC)
- seguir = FALSE;
- else
- printf ("\r \r");
- }
- } /* main */
-
- void leer_numero (char numero[])
- {
- char *puntero_al_final;
- BOOLEAN numero_correcto = FALSE;
-
- while (! numero_correcto)
- {
- printf ("\nIntroduce número: ");
- numero[0] = NUMMAXDIGITOS;
- cgets (numero);
- strtod (numero + 2, &puntero_al_final);
- if (*puntero_al_final)
- printf ("\nNúmero incorrecto.\n");
- else
- numero_correcto = TRUE;
- }
- } /* leernumero */
-
- char leer_genero (void)
- {
- char ch;
-
- printf ("\n\nGénero (M o ENTER: masculino, F: femenino): ");
- do
- {
- ch = getch ();
- } while (CARACTER_A_MAYUSCULA (ch) != 'M' &&
- CARACTER_A_MAYUSCULA (ch) != 'F' && ch != ENTER);
-
- if (ch == ENTER)
- ch = 'M';
- else
- ch = CARACTER_A_MAYUSCULA (ch);
-
- printf ("%c\n", ch);
-
- return (ch);
- } /* leergenero */
-
- void leer_columnas (int *columna1, int *columna2)
- {
- BOOLEAN columnas_correctas = FALSE;
-
- while (! columnas_correctas)
- {
- printf ("\nIntroduce las dos columnas (entre %d y %d con diferencia mínima %d): ",
- COLUMNA_MINIMA, COLUMNA_MAXIMA, DIFERENCIA_MINIMA_ENTRE_COLUMNAS);
- scanf ("%d%d", columna1, columna2);
- if (ENTRE (*columna1, COLUMNA_MINIMA, COLUMNA_MAXIMA) &&
- ENTRE (*columna2, COLUMNA_MINIMA, COLUMNA_MAXIMA) &&
- *columna2 - *columna1 + 1 >= DIFERENCIA_MINIMA_ENTRE_COLUMNAS)
- columnas_correctas = TRUE;
- else
- printf ("\nLos números de columnas introducidos son incorrectos.\n");
- }
- } /* leer_columnas */
-
- void obtener_numero (char *strnum, char gen)
- {
- char *sb, *se; /* string base y string exponente */
-
- strcpy (nomnum, "");
- /* dividir strnum en base y exponente si existe exponente */
- sb = strnum;
- se = strchr (sb, 'e');
- if (se == NULL)
- se = strchr (sb, 'E');
- if (se == NULL)
- obtener_num_sin_exp (sb, gen);
- else
- {
- *se++ = 0; /* divide el strings se en dos substrings: uno con la base y otro con el exponente */
- obtener_num_sin_exp (sb, gen);
- strcat (nomnum, POTENCIA);
- obtener_num_sin_exp (se, gen);
- }
- } /* obtener_numero */
-
- /*
- Obtiene el número correspondiente a un string sin exponente.
- */
-
- void obtener_num_sin_exp (char *s, char gen)
- {
- register char *si, *sr; /* string parte integer y string parte real */
-
- si = s;
- sr = strchr (s, '.');
- if (sr == NULL)
- obtener_parte_entera_num (s, gen);
- else
- {
- *sr++ = 0; /* divide el string sr en dos substrings: uno con parte entera y otro con parte real */
- obtener_parte_entera_num (si, gen);
- strcat (nomnum, COMA);
- obtener_parte_entera_num (sr, gen);
- }
- } /* obtener_num_sin_exp */
-
- /*
- Obtiene el número correspondiente a un string sin parte real
- */
-
- void obtener_parte_entera_num (char *s, char gen)
- {
- int grupos_tres_cifras, numdigitos, indice = 0;
- register int i, j;
- int cociente, resto, incremento;
-
- /* comprobar si hay signo */
- if (*s == '+' || *s == '-')
- strcat (nomnum, *s++ == '+' ? MAS : MENOS );
-
- for (numdigitos = 0; *s; numdigitos++, s++)
- tabnum[numdigitos] = NUM (*s);
-
- if (numdigitos == 0)
- grupos_tres_cifras = 0;
- else
- {
- /* quitar los ceros de la izquierda en la tabla de números */
- for (i = 0; i < numdigitos && tabnum[i] == 0; i++)
- ;
- if (i > 0)
- for (j = i; j < numdigitos; j++)
- tabnum [j-i] = tabnum [j];
-
- /* hallar cociente y resto para averiguar los ceros que hacen falta
- añadir a la izquierda y devolver el número de grupos de tres cifras */
- switch (numdigitos -= i)
- {
- case 0 :
- case 1 : cociente = 0;
- resto = 1;
- break;
- case 2 : cociente = 0;
- resto = 2;
- break;
- default: cociente = numdigitos / 3;
- resto = numdigitos % 3;
- }
-
- /* Se añaden los ceros a la izquierda necesarios para completar los grupos
- de tres cifras o sextetos. */
-
- /* a la variable numdigitos se le aumenta incremento que es el numero de
- ceros que hay que añadir a la izquierda cuyo valor depende del resto*/
- numdigitos += (incremento = resto == 0 ? 0 : resto == 1 ? 2 : 1);
- if (numdigitos != 3 && IMPAR (numdigitos))
- incremento += 3; /* completa sexteto (grupo de seis cifras) */
-
- /* introducir en la tabla de los números los ceros a la izquierda
- necesarios para completar el trío o sexteto */
- for (i = numdigitos - 1; i >= 0; i--)
- tabnum [i+incremento] = tabnum [i];
- for (i = 0; i < incremento; i++)
- tabnum [i] = 0;
-
- /* devolver el numero de grupos de tres cifras */
- grupos_tres_cifras = resto != 0 ? cociente + 1 : cociente;
- }
-
- obtener_nombre_de_numero (&indice, gen, grupos_tres_cifras);
- } /* obtener_parte_entera_num */
-
- void obtener_nombre_de_numero (int *indice, char genero, int grupostrescifras)
- {
- switch (grupostrescifras)
- {
- case 0 :
- strcat (nomnum, NADA);
- break;
- case 1 :
- if (*indice == 0 && numero (*indice, 3) ==0)
- strcat (nomnum, CERO);
- else
- nombre_de_numero_de_tres_cifras (indice, genero);
- break;
- case 2 :
- nombre_de_numero_de_seis_cifras (indice, genero);
- break;
- case 3 :
- case 4 :
- nombre_de_numero_de_x_cifras (indice, genero, 12, MILLON, MILLONES);
- break;
- case 5 :
- case 6 :
- nombre_de_numero_de_x_cifras (indice, genero, 18, BILLON, BILLONES);
- break;
- case 7 :
- case 8 :
- nombre_de_numero_de_x_cifras (indice, genero, 24, TRILLON, TRILLONES);
- break;
- case 9 :
- case 10:
- nombre_de_numero_de_x_cifras (indice, genero, 30, CUATRILLON, CUATRILLONES);
- break;
- case 11:
- case 12:
- nombre_de_numero_de_x_cifras (indice, genero, 36, QUINTILLON, QUINTILLONES);
- break;
- default:
- strcpy (nomnum, ERROR);
- }
- } /* obtener_nombre_de_numero */
-
- /*
- Esta función convierte unas determinadas cifras de tabnum en un número.
- Concretamente convierte las cifras de tabnum que empiezan en el índice
- ind y terminan en ind+ncifras-1.
- */
-
- int numero (int ind, int ncifras)
- {
- register int i, num;
-
- for (i = num = 0; i < ncifras; i++)
- num = 10 * num + tabnum [ind + i];
-
- return (num);
- } /* numero */
-
- /*
- Esta función convierte un número de dos cifras en texto
- */
-
- void nombre_de_numero_de_dos_cifras (int ind, char gener)
- {
- /* asigna valor al elemento de índice 1 de la tabla tabnom */
- tabnom [1] = gener == FEM ? UNA : (numdigitos - ind <= 2 ? UNO : UN);
-
- /* si número a escribir es menor que 20, leemos nombre de tabnom */
- if (numero (ind, 2) <= 20)
- strcat (nomnum, tabnom [numero (ind, 2)]);
-
- /* número mayor que 20 */
- else
- {
- /* añadimos nombre de la decena */
- strcat (nomnum, tabdec [numero (ind, 1)]);
-
- /* si no es decena de veintena y no termina en 0, añadimos Y */
- if (numero (ind + 1, 1) != 0 && numero (ind, 1) != 2)
- strcat (nomnum, Y);
-
- /* añadimos nombre de la unidad */
- strcat (nomnum, tabnom [numero (ind + 1, 1)]);
- }
- } /* nombre_de_numero_de_dos_cifras */
-
- /*
- Esta función convierte un número de tres cifras en texto
- */
-
- void nombre_de_numero_de_tres_cifras (int *indic, char genero)
- {
- /* si número de tres cifras es 0, no se hace nada */
- if (numero (*indic, 3) == 0)
- ;
-
- /* si número de tres cifras en 100, se añade CIEN */
- else if (numero (*indic, 3) == 100)
- strcat (nomnum, CIEN);
-
- /* si no es ni 0 ni 100 */
- else
- {
- /* añadimos nombre de centena */
- strcat (nomnum, genero == MASC ?
- tabcenmasc [numero (*indic, 1)] : tabcenfem [numero (*indic, 1)]);
-
- /* añadimos nombre del grupo de dos cifras restantes */
- nombre_de_numero_de_dos_cifras (*indic + 1, genero);
- }
-
- /* aumentamos índice en 3 ya que hemos procesado tres cifras de tabnum */
- *indic += 3;
- } /* nombre_de_numero_de_tres_cifras */
-
- /*
- Esta función convierte un número de seis cifras en texto
- */
-
- void nombre_de_numero_de_seis_cifras (int *indic, char genero)
- {
- /* si primeras tres cifras en 0, se procesan las tres últimas cifras */
- if (numero (*indic, 3) == 0)
- *indic += 3;
-
- /* procesar tres primeras cifras del grupo de seis */
- else
- {
- /* si valor de tres primeras cifras es 1, no se escribe nada */
- if (numero (*indic, 3) == 1)
- *indic += 3;
-
- /* escribir nombre correspondiente a las tres primeras cifras */
- else
- nombre_de_numero_de_tres_cifras (indic, genero);
-
- /* añadir MIL al nombre de las tres primeras cifras si eran distintas de 1 */
- strcat (nomnum, MIL);
- }
-
- /* escribir nombre de grupo de tres cifras */
- nombre_de_numero_de_tres_cifras (indic, genero);
- } /* nombre_de_numero_de_seis_cifras */
-
- /*
- Esta función convierte un número de x cifras en texto.
- x es mayor de 6.
- */
-
- void nombre_de_numero_de_x_cifras (int *indic, char gener, int numcifras,
- char *sustsingular, char *sustplural)
- {
- /* si valor de número a escribir es 0, no se escribe nada */
- if (numero (*indic, numcifras) == 0)
- *indic += numcifras;
-
- /* si valor de número a escribir es distinto de 0 */
- else
- {
- /* si valor de las 6 primeras cifras es 0, no se escribe nada */
- if (numero (*indic, 6) == 0)
- *indic += 6;
-
- /* si valor de las 6 primeras cifras es 1, escribir sustantivo en
- singular; por ejemplo, si trabajamos con trillones, se escribe
- TRILLON no TRILLONES */
- else if (numero (*indic, 6) == 1)
- {
- *indic += 6;
- strcat (nomnum, sustsingular);
- }
-
- /* si valor de las 6 primeras cifras es distinto de 0, llama a
- función obtener_nombre_de_numero para que escriba las 6 primeras
- cifras, que han de escribirse en masculino puesto que el género
- sólo es aplicable a las últimas cifras del número; una vez escritas
- las 6 primeras cifras se le añade el sustantivo plural, por ejemplo
- si trabajamos con trillones, se añadiría TRILLONES */
- else
- {
- obtener_nombre_de_numero (indic, MASC, 2);
- strcat (nomnum, sustplural);
- }
-
- /* una vez escritas las 6 primeras cifras junto con el sustantivo
- correspondiente, se escriben el resto de las cifras llamando a
- la función obtener_nombre_de_numero */
- obtener_nombre_de_numero (indic, gener, (numcifras -= 6) / 3);
- }
- } /* nombre_de_numero_de_x_cifras */
-
- /*
- Escribe un string entre las columnas c1 y c2 sin dividir las palabras
- del string en más de una línea.
- */
-
- void escribir (char *s, int c1, int c2)
- {
- int unsigned l; /* longitud */
- char ca = c1, /* columna actual */
- *st = s, /* s temporal, se mueve a través de s */
- *pal; /* palabra dentro de s */
-
- while (*s)
- {
- while (*s == ESPACIO)
- s++;
- if ((st = strchr (s, ESPACIO)) != NULL)
- {
- *st++ = 0;
- pal = s;
- s = st;
- }
- else
- {
- pal = s;
- *s = 0;
- }
- l = strlen (pal);
- if (l)
- if (ca == c1)
- printf ("%*c%s", c1-1, ESPACIO, pal);
- else
- if (ca + l - 1 < c2)
- printf ("%s", pal);
- else
- printf ("\n%*c%s", (ca = c1) - 1, ESPACIO, pal);
- ca += l;
- if (ca < c2)
- {
- putchar (' ');
- ca++;
- }
- }
- putchar ('\n');
- } /* escribir */
- ende
- end lección 7
-
- ; LECCION 8
- begin
- begine " PROGRAMA PARA PROBAR OPERACIONES CON UNA LISTA "
- /*
- Ya dijimos en la teoría de la lección anterior que a veces necesitamos
- utilizar arrays dinámicos (su tamaño se determina en tiempo de ejecución)
- en vez de arrays estáticos (su tamaño se determina en tiempo de compilación);
- pero en ambos casos necesitamos saber el tamaño del array y en muchas apli-
- caciones no se sabe. Este problema se soluciona con las estructuras dinámi-
- cas de datos, en ellas vamos asignando y liberando memoria conforme a nues-
- tras necesidades.
-
- La forma más simple de relacionar o enlazar un conjunto de elementos es
- alinearlos formando una única lista pues, en este caso, se necesita única-
- mente un enlace por elemento, para referenciar su sucesor.
-
- Una lista la podemos representar gráficamente del siguiente modo:
-
- puntero a cabeza
- |
- |
- v
- ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
- │ información │ │ información │ │ información │
- ├─────────────┤ ├─────────────┤ ├─────────────┤
- │ puntero ------>│ puntero ------> ...... ------>│ NULL │
- └─────────────┘ └─────────────┘ └─────────────┘
-
- En este programa se trabaja con una lista como la mostrada. Pero también
- se utiliza mucho otras listas más complejas:
-
- - Lista circular: el puntero al siguiente nodo del último nodo apunta
- al primer nodo. En este caso el puntero que apunta a la lista, apunta
- al último nodo de la lista, y se accede al primer elemento de la lista
- como el puntero siguiente al puntero a la lista.
-
- - Lista doblemente enlazada: en cada nodo, además de haber un puntero
- al siguiente nodo, también hay un puntero al anterior nodo. Puede
- ser lineal o circular.
-
- - Listas ordenadas: están ordenadas por algún criterio, de este modo
- las búsquedas (para consultas, inserciones, borrados, ...) son más
- rápidas.
-
- - Pilas y colas: son listas lineales simplemente enlazadas y circulares
- en las que la consulta de un nodo implica la supresión de ese nodo y
- sigue una regla: en las pilas se saca aquel elemento que entró el últi-
- mo y en las colas se saca aquel elemento que entró el último.
-
- Observaciones sobre el programa:
-
- 1) Si pasamos un puntero por valor como argumento a una función (por
- ejemplo, parbol de la función main) podemos modificar el contenido de
- la dirección a la que apunta pero no la dirección a la que apunta. Para
- poder modificar también la dirección a la que apunta ese puntero pasado
- como argumento tenemos que pasarlo por referencia, es decir, pasar su
- dirección. Si la función empezar_lista() la hubiésemos definido así:
-
- void empezar_lista (pnl plist)
- {
- plist = NULL;
- }
-
- estamos asignando el valor NULL a la variable local plist pero no a la
- variable plista de la función main, con lo cual el programa no funcionaría
- correctamente.
-
- 2) La función strrchr() de la librería <string.h> ya la vimos en los dos
- ejemplos de la escritura alfabética de números en la lección anterior.
- Esta función acepta un string y un carácter, y devuelve un puntero a la
- primera ocurrencia de ese carácter en el string dado, si el carácter no
- se encuentra la función devuelve NULL.
- */
-
- /* Ficheros a incluir: */
-
- #include <stdio.h> /* printf (), scanf (), puts () */
- #include <conio.h> /* getch () */
- #include <stdlib.h> /* exit () */
- #include <alloc.h> /* malloc (), free () */
- #include <string.h> /* strchr () */
-
- /* Estructuras y tipos globales: */
-
- struct nodo_lista
- {
- int informacion;
- struct nodo_lista *psiguiente;
- };
-
- typedef struct nodo_lista nl; /* nl: nodo lista */
- typedef nl *pnl; /* pnl: puntero a nodo lista */
-
- /* Macros: */
-
- #define inform(p) ((p)->informacion) /* información apuntada por p */
- #define psig(p) ((p)->psiguiente) /* puntero al siguiente apuntado por p */
-
- #define BOOLEAN int
- #define TRUE 1
- #define FALSE 0
-
- #define ESC ''
-
- #define intercambiar(x,y) { int z; z = (x); (x) = (y); (y) = z; }
-
- /* Prototipos de las funciones: */
-
- void empezar_lista (pnl *plist);
- void terminar_lista (pnl *plist);
- void crear_nodo_lista (pnl *pl);
- void liberar_nodo_lista (pnl *pl);
- void aniadir_a_lista (pnl *plist, int info);
- BOOLEAN quitar_de_lista (pnl *plist, int info);
- pnl buscar_en_lista (pnl plist, int info);
- void listar_lista (pnl plist);
- void ordenar_lista (pnl *plist);
- void insertar_en_orden_en_lista (pnl *plist, pnl pl);
- void insertar_delante_en_lista (pnl *plist, pnl pl, pnl p);
- void insertar_detras_en_lista (pnl pl, pnl p);
-
- /* Definición de funciones: */
-
- /*
- Función principal.
- */
-
- void main (void)
- {
- BOOLEAN salir = FALSE;
- char ch;
- pnl plista;
- int num;
-
- puts ("\nPROGRAMA PARA PROBAR OPERACIONES CON UNA LISTA.");
- empezar_lista (&plista);
- do
- {
- printf ("\nOperación a realizar (Añadir, Quitar, Buscar, Listar, Ordenar, Salir): ");
- do
- {
- ch = getch ();
- } while (strchr ("aAqQbBlLoOsS", ch) == NULL);
- switch (putch (ch))
- {
- case 'a':
- case 'A':
- printf ("\n\nIntroduce número a añadir: ");
- scanf ("%d", &num);
- aniadir_a_lista (&plista, num);
- break;
- case 'q':
- case 'Q':
- printf ("\n\nIntroduce número a quitar: ");
- scanf ("%d", &num);
- if (quitar_de_lista (&plista, num))
- printf ("\nNúmero %d quitado de la lista.\n", num);
- else
- printf ("\nEl número %d no se encuentra en la lista.\n", num);
- break;
- case 'b':
- case 'B':
- printf ("\n\nIntroduce número a buscar: ");
- scanf ("%d", &num);
- printf ("\nNúmero %d%sencontrado.\n", num,
- buscar_en_lista (plista, num) != NULL ? " " : " no ");
- break;
- case 'l':
- case 'L':
- listar_lista (plista);
- break;
- case 'o':
- case 'O':
- ordenar_lista (&plista);
- listar_lista (plista);
- break;
- case 's':
- case 'S':
- case ESC:
- salir = TRUE;
- }
- } while (! salir);
- terminar_lista (&plista);
- }
-
- /*
- La primera operación que hay que hacer siempre con una lista es inicializarla,
- esto consiste en asignar NULL al puntero que apunta a la cabeza de la lista
- */
-
- void empezar_lista (pnl *plist)
- {
- *plist = NULL;
- }
-
- /*
- Antes de acabar el programa es conveniente liberar la memoria asignada
- dinámicamente. Para ello, lo único que se hace es recorrer toda la
- lista liberando cada nodo con free().
- */
-
- void terminar_lista (pnl *plist)
- {
- pnl p;
-
- p = *plist;
- while (p) /* recorre toda la lista liberando cada nodo */
- {
- *plist = psig (p);
- liberar_nodo_lista (&p);
- p = *plist;
- }
- }
-
- /*
- Asigna memoria para un nodo de la lista.
- Si no hay suficiente memoria, el programa presenta un mensaje de error
- y termina.
- */
-
- void crear_nodo_lista (pnl *pl)
- {
- if ((*pl = (pnl) malloc (sizeof (nl))) == NULL)
- {
- printf ("\nERROR: Memoria insuficiente.");
- exit (1);
- }
- }
-
- /*
- Libera memoria asignada con malloc, de este modo esta memoria puede
- ser reutilizada.
- */
-
- void liberar_nodo_lista (pnl *pl)
- {
- free (*pl);
- }
-
- /*
- Añade un nodo al principio de la lista. Al tratarse de una lista desordenada
- no tiene importancia el lugar en que insertamos el nodo; sin embargo, inser-
- tarlo al principio es la inserción más rápida.
- */
-
- void aniadir_a_lista (pnl *plist, int info)
- {
- pnl p;
-
- crear_nodo_lista (&p);
- inform (p) = info;
- psig (p) = *plist;
- *plist = p;
- }
-
- /*
- Quita el primer nodo encontrado que contenga el valor info en el
- campo información del nodo.
- Devuelve TRUE si se borró el elemento o FALSE en caso contrario.
- */
-
- BOOLEAN quitar_de_lista (pnl *plist, int info)
- {
- pnl p = *plist, pant = NULL;
- BOOLEAN elemento_quitado;
-
- while (p != NULL && inform (p) != info) /* busca elemento */
- {
- pant = p;
- p = psig (p);
- }
-
- if (p == NULL) /* si hemos llegado al final de la lista, elemento no encontrado */
- elemento_quitado = FALSE;
- else
- {
- elemento_quitado = TRUE;
- (pant == NULL ? *plist : psig (pant)) = psig (p); /* dos casos: primer nodo u otro nodo */
- liberar_nodo_lista (&p);
- }
-
- return (elemento_quitado);
- }
-
- /*
- Devuelve TRUE si info se encuentra en un nodo de la lista, y FALSE en
- caso contrario.
- */
-
- pnl buscar_en_lista (pnl plist, int info)
- {
- pnl p = plist;
-
- while (p != NULL && inform (p) != info) /* búsqueda del elemento en la lista */
- p = psig (p);
-
- return (p); /* p valdrá NULL si info no se ha encontrado */
- }
-
- /*
- Imprime todos los elementos de la lista.
- */
-
- void listar_lista (pnl plist)
- {
- printf ("\n\nElementos en lista: ");
- if (plist == NULL)
- printf ("(ninguno)");
- else
- {
- pnl p;
- for (p = plist; p != NULL; p = psig (p)) /* recorre todos los nodos */
- printf ("%d ", inform(p));
- }
- puts (""); /* esta sentencia es equivalente a putch ('\n') y printf ("\n") */
- }
-
- /*
- Ordena la lista de menor a mayor.
- */
-
- void ordenar_lista (pnl *plist)
- {
- pnl p1, p2;
-
- if (*plist != NULL)
- {
- p1 = psig (*plist);
- psig (*plist) = NULL;
- while (p1 != NULL) /* a partir de segundo nodo, va insertando ... */
- { /* ... cada nodo en la primera parte de la lista de una forma ordenada */
- p2 = psig (p1);
- insertar_en_orden_en_lista (plist, p1);
- p1 = p2;
- }
- }
- }
-
- /*
- Inserta el nodo pl en una lista ordenada de menor a mayor.
- */
-
- void insertar_en_orden_en_lista (pnl *plist, pnl pl)
- {
- psig (pl) = NULL;
- if (*plist == NULL)
- *plist = pl;
- else
- {
- pnl p = *plist;
- while (inform (p) < inform (pl) && psig (p) != NULL) /* busca sitio donde insertar */
- p = psig (p);
- if (inform (p) >= inform (pl)) /* dos formas de insertar */
- insertar_delante_en_lista (plist, p, pl);
- else
- insertar_detras_en_lista (p, pl);
- }
- }
-
- /*
- Inserta el nodo p delante del nodo pl en lista encabezada por plist.
- */
-
- void insertar_delante_en_lista (pnl *plist, pnl pl, pnl p)
- {
- if (pl == *plist)
- {
- psig (p) = *plist;
- *plist = p;
- }
- else
- {
- psig (p) = psig (pl);
- psig (pl) = p;
- intercambiar (inform (pl), inform (p));
- }
- }
-
- /*
- Inserta el nodo p detrás del nodo pl.
- */
-
- void insertar_detras_en_lista (pnl pl, pnl p)
- {
- psig (p) = psig (pl);
- psig (pl) = p;
- }
-
- #undef inform
- #undef psig
- #undef BOOLEAN
- #undef TRUE
- #undef FALSE
- #undef ESC
- #undef intercambiar
- ende
- begine " PROGRAMA PARA PROBAR OPERACIONES CON UN ARBOL "
- /*
- La estructura de árbol binario (aquél en que cada nodo tiene dos hijos)
- suele ser más utilizada que las listas ordenadas (no tiene sentido un
- árbol no ordenado) porque el acceso a un determinado elemento es mucho
- más rápido (en términos de media) que en tales listas.
-
- Un árbol binario lo podemos representar gráficamente de la siguiente forma:
-
- puntero a cabeza
- |
- |
- v
- ┌─────────────┐
- │ información │
- ├──────┬──────┤
- │ pizq │ pder │
- └──────┴──────┘
- / \
- / \
- / \
- / \
- ┌─────────────┐ ┌─────────────┐
- │ información │ │ información │
- ├──────┬──────┤ ├──────┬──────┤
- │ pizq │ pder │ │ pizq │ pder │
- └──────┴──────┘ └──────┴──────┘
- / \ / \
- / \ / \
- ... ... ... ...
- */
-
- /* Ficheros a incluir: */
-
- #include <stdio.h> /* printf (), scanf (), puts () */
- #include <conio.h> /* getch () */
- #include <stdlib.h> /* exit () */
- #include <alloc.h> /* malloc (), free () */
- #include <string.h> /* strchr () */
-
- /* Estructuras y tipos globales: */
-
- struct nodo_arbol
- {
- int informacion;
- struct nodo_arbol *pizquierda, *pderecha;
- };
-
- typedef struct nodo_arbol na; /* na: nodo árbol */
- typedef na *pna; /* pna: puntero a nodo árbol */
-
- /* Macros: */
-
- #define inform(p) ((p)->informacion) /* información apuntada por p */
- #define pizq(p) ((p)->pizquierda) /* puntero al nodo izquierdo apuntado por p */
- #define pder(p) ((p)->pderecha) /* puntero al nodo derecho apuntado por p */
-
- #define BOOLEAN int
- #define TRUE 1
- #define FALSE 0
-
- #define ESC ''
-
- /* Prototipos de las funciones: */
-
- void empezar_arbol (pna *parb);
- void terminar_arbol (pna *parb);
- void crear_nodo_arbol (pna *pa);
- void liberar_nodo_arbol (pna *pa);
- void aniadir_a_arbol (pna *parb, int info);
- BOOLEAN quitar_de_arbol (pna *parb, int info);
- void suprimir_nodo_de_arbol (pna *p);
- pna buscar_en_arbol (pna parb, int info);
- void imprimir_arbol_en_preorden (pna parb);
- void imprimir_arbol_en_postorden (pna parb);
- void imprimir_arbol_en_inorden (pna parb);
-
- /* Definición de funciones: */
-
- /*
- Función principal.
- */
-
- void main (void)
- {
- BOOLEAN salir = FALSE;
- char ch;
- pna parbol;
- int num;
-
- puts ("\nPROGRAMA PARA PROBAR OPERACIONES CON UN ARBOL.");
- empezar_arbol (&parbol);
- do
- {
- printf ("\nOperación a realizar (Añadir, Quitar, Buscar, Listar, Salir): ");
- do
- {
- ch = getch ();
- } while (strchr ("aAqQbBlLsS", ch) == NULL);
- switch (putch (ch))
- {
- case 'a':
- case 'A':
- printf ("\n\nIntroduce número a añadir: ");
- scanf ("%d", &num);
- aniadir_a_arbol (&parbol, num);
- break;
- case 'q':
- case 'Q':
- printf ("\n\nIntroduce número a quitar: ");
- scanf ("%d", &num);
- if (quitar_de_arbol (&parbol, num))
- printf ("\nNúmero %d quitado del árbol.\n", num);
- else
- printf ("\nEl número %d no se encuentra en el árbol.\n", num);
- break;
- case 'b':
- case 'B':
- printf ("\n\nIntroduce número a buscar: ");
- scanf ("%d", &num);
- printf ("\nNúmero %d%sencontrado.\n", num,
- buscar_en_arbol (parbol, num) != NULL ? " " : " no ");
- break;
- case 'l':
- case 'L':
- printf ("\nTipo de recorrido (Preorden, posTorden, Inorden): ");
- do
- {
- ch = getch ();
- } while (strchr ("pPtTiI", ch) == NULL);
- putch (ch);
- printf ("\n\nElementos en árbol: ");
- if (parbol == NULL)
- printf ("(ninguno)");
- else
- switch (ch)
- {
- case 'p':
- case 'P':
- imprimir_arbol_en_preorden (parbol);
- break;
- case 't':
- case 'T':
- imprimir_arbol_en_postorden (parbol);
- break;
- case 'i':
- case 'I':
- imprimir_arbol_en_inorden (parbol);
- break;
- }
- puts ("");
- break;
- case 's':
- case 'S':
- case ESC:
- salir = TRUE;
- }
- } while (! salir);
- terminar_arbol (&parbol);
- }
-
- /*
- La primera operación que hay que hacer siempre con un árbol es inicializarlo,
- esto consiste en asignar NULL al puntero que apunta a la cabeza del árbol.
- */
-
- void empezar_arbol (pna *parb)
- {
- *parb = NULL;
- }
-
- /*
- Antes de acabar el programa es conveniente liberar la memoria asignada
- dinámicamente. Para ello, lo único que se hace es recorrer todo el
- árbol liberando cada nodo con free().
- */
-
- void terminar_arbol (pna *parb)
- {
- if (*parb != NULL)
- {
- terminar_arbol (&pizq(*parb));
- terminar_arbol (&pder(*parb));
- liberar_nodo_arbol (parb);
- }
- }
-
- /*
- Asigna memoria para un nodo del árbol.
- Si no hay suficiente memoria, el programa presenta un mensaje de error
- y termina.
- */
-
- void crear_nodo_arbol (pna *pa)
- {
- if ((*pa = (pna) malloc (sizeof (na))) == NULL)
- {
- printf ("\nERROR: Memoria insuficiente.");
- exit (1);
- }
- }
-
- /*
- Libera memoria asignada con malloc, de este modo esta memoria puede
- ser reutilizada.
- */
-
- void liberar_nodo_arbol (pna *pa)
- {
- free (*pa);
- }
-
- /*
- Para ver cómo se inserta en lo árboles, veamos cómo se insertarían
- los siguientes números en un árbol donde información es un número
- entero:
-
- 3 10 2 -1 0 3 8 20
-
- Paso 0:
- parbol
- │
- v
- NULL
- Paso 1:
- parbol
- │
- v
- 3
- Paso 2:
- parbol
- │
- v
- 3
- \
- 10
- Paso 3:
- parbol
- │
- v
- 3
- / \
- 2 10
- Paso 4:
- parbol
- │
- v
- 3
- / \
- 2 10
- /
- -1
- Paso 5:
- parbol
- │
- v
- 3
- / \
- 2 10
- /
- -1
- \
- 0
- Paso 6:
- parbol
- │
- v
- 3
- / \
- 2 10
- / /
- -1 3
- \
- 0
- Paso 7:
- parbol
- │
- v
- 3
- / \
- 2 10
- / /
- -1 3
- \ \
- 0 8
- Paso 8:
- parbol
- │
- v
- 3
- / \
- 2 10
- / / \
- -1 3 20
- \ \
- 0 8
-
- */
-
- void aniadir_a_arbol (pna *parb, int info)
- {
- pna p, pant; /* punteros utilizados para la búsqueda */
- pna pa; /* puntero que apunta a nuevo nodo creado y que hay que insertar */
-
- crear_nodo_arbol (&pa);
- inform (pa) = info;
- pizq (pa) = pder (pa) = NULL;
-
- p = *parb;
- pant = NULL;
- while (p != NULL) /* busca lugar de inserción */
- {
- pant = p;
- if (inform (p) > info)
- p = pizq (p);
- else
- p = pder (p);
- }
-
- if (pant == NULL) /* inserta en lugar correspondiente */
- *parb = pa;
- else if (inform (pant) > info)
- pizq (pant) = pa;
- else
- pder (pant) = pa;
- }
-
- /*
- Quita el primer nodo encontrado que contenga el valor info en el
- campo información del nodo.
- Devuelve TRUE si se borró el elemento o FALSE en caso contrario.
- */
-
- BOOLEAN quitar_de_arbol (pna *parb, int info)
- {
- pna p = *parb, pant = NULL;
- BOOLEAN encontrado = FALSE;
-
- while (p != NULL && ! encontrado) /* busca nodo a borrar */
- if (inform (p) == info)
- encontrado = TRUE;
- else
- {
- pant = p;
- if (inform (p) > info)
- p = pizq (p);
- else
- p = pder (p);
- }
-
- if (encontrado) /* llama a la función suprimir con puntero apuntado a nodo a quitar */
- if (p == *parb)
- suprimir_nodo_de_arbol (parb);
- else if (pizq (pant) == p)
- suprimir_nodo_de_arbol (&pizq(pant));
- else
- suprimir_nodo_de_arbol (&pder(pant));
-
- return (encontrado);
- }
-
- /*
- Suprime nodo de árbol apuntado por p.
- Esta función es llamada por la función quitar_de_arbol.
-
- Hay tres situaciones diferentes a la hora de suprimir un nodo, a saber:
-
- Sea el árbol compuesto de números reales:
-
- 5
- / \
- 3 8
- / \ / \
- 2 4 6 9
- / / \
- 1 5.5 7
- /
- 6.5
-
- Situación 1: suprimir nodo sin hijo derecho; por ejemplo, el nodo 7, en
- este caso el puntero p es el puntero derecho del nodo 6; la acción a
- realizar es: p = pizq (p).
-
- Situación 2: suprimir nodo sin hijo izquierdo; por ejemplo, el nodo 1, en
- este caso el puntero p es el puntero izquierdo del nodo 2; la acción a
- realizar es: p = pder (p).
-
- Situación 3: suprimir nodo intermedio, es decir, nodo con hijos izquierdo
- y derecho; por ejemplo, el nodo 8, en este caso el puntero p es el
- puntero derecho del nodo 5; la acción a realizar es sustituir el contenido
- del nodo a suprimir (nodo 8) por el mayor contenido entre los nodos del
- subárbol izquierdo, que se calcula como el nodo más a la derecha a partir
- del nodo izquierdo del nodo a suprimir, en este caso el nodo izquierdo es
- 6 y recorriendo los punteros a la derecha hasta llegar al final, nos
- paramos en el nodo 7, copiamos el contenido del nodo 7 en el nodo 8 y
- ahora tenemos que suprimir un nodo (el 7 en este caso) que ya pertenece
- a uno de los dos casos anteriores.
- */
-
- void suprimir_nodo_de_arbol (pna *p)
- {
- pna ptemp = *p;
-
- if (pder (*p) == NULL) /* situación 1 */
- *p = pizq (*p);
- else if (pizq (*p) == NULL) /* situación 2 */
- *p = pder (*p);
- else /* situación 3 */
- {
- pna pant = *p;
- ptemp = pizq (*p);
- while (pder (ptemp) != NULL) /* recorremos punteros a derecha a partir ... */
- { /* ... puntero a izquierda del nodo apuntado por el puntero a suprimir */
- pant = ptemp;
- ptemp = pder (ptemp);
- }
- inform (*p) = inform (ptemp);
- if (pant == *p)
- pizq (pant) = pizq (ptemp);
- else
- pder (pant) = pizq (ptemp);
- }
-
- liberar_nodo_arbol (&ptemp);
- }
-
- /*
- Devuelve un puntero al nodo del árbol que contiene dat. Si ningún nodo
- del árbol contiene el dato dat, devuelve NULL.
- */
-
- pna buscar_en_arbol (pna parb, int info)
- {
- pna p = parb;
- BOOLEAN encontrado = FALSE;
-
- while (p != NULL && ! encontrado)
- if (inform (p) == info)
- encontrado = TRUE;
- else if (inform (p) > info)
- p = pizq (p);
- else
- p = pder (p);
-
- return (p); /* p valdrá NULL si info no se ha encontrado */
- }
-
- /*
- Imprime todos los elementos del árbol haciendo un recorrido en preorden.
- */
-
- void imprimir_arbol_en_preorden (pna parb)
- {
- if (parb != NULL)
- {
- printf ("%d ", inform (parb));
- imprimir_arbol_en_preorden (pizq (parb)); /* imprime subárbol izquierdo */
- imprimir_arbol_en_preorden (pder (parb)); /* imprime subárbol derecho */
- }
- }
-
- /*
- Imprime todos los elementos del árbol haciendo un recorrido en postorden.
- */
-
- void imprimir_arbol_en_postorden (pna parb)
- {
- if (parb != NULL)
- {
- imprimir_arbol_en_postorden (pizq (parb)); /* imprime subárbol izquierdo */
- imprimir_arbol_en_postorden (pder (parb)); /* imprime subárbol derecho */
- printf ("%d ", inform (parb));
- }
- }
-
- /*
- Imprime todos los elementos del árbol haciendo un recorrido en inorden.
- Si el árbol está ordenado, este recorrido imprime los elmentos ordenados.
- */
-
- void imprimir_arbol_en_inorden (pna parb)
- {
- if (parb != NULL)
- {
- imprimir_arbol_en_inorden (pizq (parb)); /* imprime subárbol izquierdo */
- printf ("%d ", inform (parb));
- imprimir_arbol_en_inorden (pder (parb)); /* imprime subárbol derecho */
- }
- }
-
- #undef inform
- #undef pder
- #undef pizq
- #undef BOOLEAN
- #undef TRUE
- #undef FALSE
- #undef ESC
- ende
- begine " PROGRAMA PARA PROBAR OPERACIONES CON UNA TABLA HASH "
- /*
- Uno de los métodos más rápidos para acceder a elementos de tipo string
- que estén ordenados según algún criterio es mediante la técnica hash. En
- realidad, los elementos no tienen porqué ser de tipo string, pero es más
- utilizado en estos casos.
-
- Esta técnica consiste en lo siguiente:
-
- 1. Tenemos una tabla del tamaño que queramos. Cuantas más entradas
- tenga la tabla, el método será más eficiente.
-
- 2. Cada elemento de la tabla es un puntero a otra tabla hash, a una
- lista (preferible ordenada), a un árbol o a cualquier otra estructura
- donde guardar los strings correspondiente a esa entrada de la tabla.
- En este programa, cada elemento de la tabla apunta a la cabeza de una
- lista ordenada de menor a mayor de strings. También hubiera sido una
- buena estructura un árbol binario.
-
- 3. Cuando queremos acceder a un determinado string (para búsqueda,
- inserción, supresión, ... del string) obtenemos su clave hash; esta
- clave hash es un número que corresponde a un índice de la tabla. Una
- vez obtenida la clave hash del string, ya tenemos el índice de la
- tabla en el cual está (debe de estar) el string. Una buena clave para
- los strings es el resto (módulo) de dividir la suma de los valores
- ascii de los caracteres del string entre el número de elementos de
- la tabla. De esta forma la clave hash siempre corresponde a un índice
- válido de la tabla. Según esta fórmula los strings "abc" y "bca"
- tienen la misma clave, esto significa, que estos dos strings están
- en una misma lista (recordar que cada entrada de la tabla apunta a
- una lista distinta de strings). En este programa también se observa
- que la información contenido en cada nodo de la lista es un puntero
- al string, donde la memoria ocupada por este string es asignada
- dinámicamente y por lo tanto ha de ser liberada dinámicamente.
-
- Observaciones:
-
- 1) Las funciones de operaciones con lista son similares a las que hemos
- visto en el primer ejemplo. Allí se explican más que aquí.
-
- 2) Hemos utilizado dos funciones de la librería <string.h> que merecen
- una explicación:
-
- · int strcmp (const char *s1, const char *s2);
-
- Esta función compara los strings s1 y s2. Devuelve uno de los
- siguientes valores:
-
- < 0 si s1 es menor que s2
- == 0 si s1 es igual que s2
- > 0 si s1 es mayor que s2
-
- · char *strdup (const char *s);
-
- Esta función obtiene una copia duplicada de s, o copia s a una
- nueva localización. Devuelve un puntero a s duplicado, o devuelve
- NULL si no se puedo asignar espacio para la copia. El programador
- es responsable de liberar el espacio asignado por strdup cuando ya
- no haga falta.
-
- Esta función es parecida a malloc() con la diferencia de que strdup
- además de reservar memoria, copia el string s a la nueva memoria
- reservada.
- */
-
- /* Ficheros a incluir: */
-
- #include <conio.h> /* getch () */
- #include <stdio.h> /* printf (), scanf (), NULL */
- #include <alloc.h> /* malloc (), free () */
- #include <string.h> /* strdup (), strcmp () */
- #include <stdlib.h> /* exit () */
-
- /* Macros: */
-
- #define NUM_ELEMENTOS_TABLA_HASH 255
- #define NUM_MAX_CARACTERES_FRASE 255
-
- #define BOOLEAN int
- #define TRUE 1
- #define FALSE 0
-
- #define ESC 27
-
- #define intercambiar(s1,s2) { char *s3; s3 = (s1); (s1) = (s2); (s2) = s3; }
-
- /* Tipos de datos y macros: */
-
- struct struct_nodolista
- {
- char *frase;
- struct struct_nodolista *psiguiente;
- };
-
- typedef struct struct_nodolista nodolista;
- typedef nodolista *p_nodolista;
- typedef p_nodolista tabla_hash [NUM_ELEMENTOS_TABLA_HASH];
-
- #define frase(p) ((p)->frase)
- #define psig(p) ((p)->psiguiente)
-
- /* Prototipos de las funciones: */
-
- int clave_hash (char *string);
- void empezar_tabla_hash (tabla_hash tabla);
- void terminar_tabla_hash (tabla_hash tabla);
- void liberar_lista_tabla_hash (p_nodolista *plista);
- void liberar_nodo_lista_tabla_hash (p_nodolista *pl);
- void crear_nodo_lista (p_nodolista *pl);
- void insertar_en_lista_tabla_hash (p_nodolista *plista, char *frase);
- void insertar_en_orden_en_lista_tabla_hash (p_nodolista *plista, p_nodolista pl);
- void insertar_delante_en_lista_tabla_hash (p_nodolista *plista,
- p_nodolista pl, p_nodolista p);
- void insertar_detras_en_lista_tabla_hash (p_nodolista pl, p_nodolista p);
- void insertar_en_tabla_hash (tabla_hash tabla, char *frase);
- p_nodolista buscar_en_lista_tabla_hash (p_nodolista plista, char *frase);
- p_nodolista buscar_en_tabla_hash (tabla_hash tabla, char *frase);
- void listar_lista_tabla_hash (p_nodolista plista);
- void listar_tabla_hash (tabla_hash tabla);
- BOOLEAN quitar_de_lista_tabla_hash (p_nodolista *plista, char *frase);
- BOOLEAN quitar_de_tabla_hash (tabla_hash tabla, char *frase);
- void error_de_memoria (void);
-
- /* Definición de las funciones: */
-
- /*
- Función principal.
- */
-
- void prlec8_3 (void)
- {
- tabla_hash tabla_hash;
- BOOLEAN salir = FALSE;
- char ch;
- char frase[NUM_MAX_CARACTERES_FRASE];
-
- puts ("\nPROGRAMA PARA PROBAR OPERACIONES CON UNA TABLA HASH.");
- empezar_tabla_hash (tabla_hash);
- do
- {
- printf ("\nOperación a realizar (Insertar, Quitar, Buscar, Listar, Salir): ");
- do
- {
- ch = getch ();
- } while (strchr ("iIqQbBlLsS", ch) == NULL);
- switch (putch (ch))
- {
- case 'i':
- case 'I':
- printf ("\n\nIntroduce frase a añadir: ");
- scanf ("%s", frase);
- insertar_en_tabla_hash (tabla_hash, frase);
- break;
- case 'q':
- case 'Q':
- printf ("\n\nIntroduce frase a quitar: ");
- scanf ("%s", frase);
- if (quitar_de_tabla_hash (tabla_hash, frase))
- printf ("\nFrase \"%s\" quitada de la tabla hash.\n", frase);
- else
- printf ("\nLa frase \"%s\" no se encuentra en la tabla hash.\n", frase);
- break;
- case 'b':
- case 'B':
- printf ("\n\nIntroduce frase a buscar: ");
- scanf ("%s", frase);
- printf ("\nFrase \"%s\"%sencontrado.\n", frase,
- buscar_en_tabla_hash (tabla_hash, frase) != NULL ? " " : " no ");
- break;
- case 'l':
- case 'L':
- listar_tabla_hash (tabla_hash);
- break;
- case 's':
- case 'S':
- case ESC:
- salir = TRUE;
- }
- } while (! salir);
- terminar_tabla_hash (tabla_hash);
- }
-
- /*
- Devuelve la clave hash de un determinado string.
- */
-
- int clave_hash (char *string)
- {
- register int suma_ascii;
- char *p;
-
- for (suma_ascii = 0, p = string; *p; p++)
- suma_ascii += *p;
-
- return ((suma_ascii) % (NUM_ELEMENTOS_TABLA_HASH));
- }
-
- /*
- Inicializa elementos de la tabla hash.
- */
-
- void empezar_tabla_hash (tabla_hash tabla)
- {
- register int i;
-
- for (i = 0; i < NUM_ELEMENTOS_TABLA_HASH; i++)
- tabla[i] = NULL;
- }
-
- /*
- Libera memoria asignada dinámicamente en tabla hash.
- */
-
- void terminar_tabla_hash (tabla_hash tabla)
- {
- register int i;
-
- for (i = 0; i < NUM_ELEMENTOS_TABLA_HASH; i++)
- liberar_lista_tabla_hash (&tabla[i]);
- }
-
- /*
- Libera memoria asignada dinámicamente de una lista.
- */
-
- void liberar_lista_tabla_hash (p_nodolista *plista)
- {
- p_nodolista p;
-
- p = *plista;
- while (p != NULL)
- {
- *plista = psig (p);
- liberar_nodo_lista_tabla_hash (&p);
- p = *plista;
- }
- }
-
- /*
- Libera de memoria un nodo de una lista.
- */
-
- void liberar_nodo_lista_tabla_hash (p_nodolista *pl)
- {
- if (frase (*pl) != NULL)
- free (frase (*pl));
- free (*pl);
- }
-
- /*
- Asigna memoria para un nodo de una lista.
- */
-
- void crear_nodo_lista (p_nodolista *pl)
- {
- if ((*pl = (p_nodolista) malloc (sizeof (nodolista))) == NULL)
- error_de_memoria ();
- }
-
- /*
- Inserta una frase en la tabla hash.
- */
-
- void insertar_en_lista_tabla_hash (p_nodolista *plista, char *frase)
- {
- p_nodolista p;
-
- crear_nodo_lista (&p);
- if ((frase (p) = strdup (frase)) == NULL)
- error_de_memoria ();
- insertar_en_orden_en_lista_tabla_hash (plista, p);
- }
-
- /*
- Inserta una frase en orden en una lista.
- */
-
- void insertar_en_orden_en_lista_tabla_hash (p_nodolista *plista, p_nodolista pl)
- {
- psig (pl) = NULL;
- if (*plista == NULL)
- *plista = pl;
- else
- {
- p_nodolista p = *plista;
- while (strcmp (frase (p), frase (pl)) < 0 && psig (p) != NULL)
- p = psig (p);
- if (strcmp (frase (p), frase (pl)) >= 0)
- insertar_delante_en_lista_tabla_hash (plista, p, pl);
- else
- insertar_detras_en_lista_tabla_hash (p, pl);
- }
- }
-
- /*
- Inserta el nodo p delante del nodo pl en lista encabezada por *plista.
- */
-
- void insertar_delante_en_lista_tabla_hash (p_nodolista *plista,
- p_nodolista pl, p_nodolista p)
- {
- if (pl == *plista)
- {
- psig (p) = *plista;
- *plista = p;
- }
- else
- {
- psig (p) = psig (pl);
- psig (pl) = p;
- intercambiar (frase (pl), frase (p));
- }
- }
-
- /*
- Inserta el nodo p detrás del nodo pl.
- */
-
- void insertar_detras_en_lista_tabla_hash (p_nodolista pl, p_nodolista p)
- {
- psig (p) = psig (pl);
- psig (pl) = p;
- }
-
- /*
- Inserta una frase en la tabla hash.
- */
-
- void insertar_en_tabla_hash (tabla_hash tabla, char *frase)
- {
- int valor_hash;
-
- valor_hash = clave_hash (frase);
- insertar_en_lista_tabla_hash (&tabla[valor_hash], frase);
- }
-
- /*
- Busca una frase en una lista.
- */
-
- p_nodolista buscar_en_lista_tabla_hash (p_nodolista plista, char *frase)
- {
- p_nodolista p = plista;
-
- while (p != NULL && strcmp (frase, frase (p)) < 0)
- p = psig (p);
-
- return (p != NULL && strcmp (frase, frase (p)) == 0 ? p : NULL);
- }
-
- /*
- Busca una frase en la tabla hash.
- */
-
- p_nodolista buscar_en_tabla_hash (tabla_hash tabla, char *frase)
- {
- int valor_hash;
-
- valor_hash = clave_hash (frase);
- return (buscar_en_lista_tabla_hash (tabla[valor_hash], frase));
- }
-
- /*
- Lista todas las frases contenidas en una lista.
- */
-
- void listar_lista_tabla_hash (p_nodolista plista)
- {
- p_nodolista p;
- for (p = plista; p != NULL; p = psig (p))
- puts (frase (p));
- }
-
- /*
- Lista todas las frases que hay en la tabla hash.
- */
-
- void listar_tabla_hash (tabla_hash tabla)
- {
- register int i;
-
- printf ("\n\nElementos en listas de tabla hash:\n\n");
- for (i = 0; i < NUM_ELEMENTOS_TABLA_HASH; i++)
- listar_lista_tabla_hash (tabla[i]);
- puts ("");
- }
-
- /*
- Quita una frase de una lista.
- */
-
- BOOLEAN quitar_de_lista_tabla_hash (p_nodolista *plista, char *frase)
- {
- p_nodolista p = *plista, pant = NULL;
- BOOLEAN elemento_quitado;
-
- while (p != NULL && strcmp (frase, frase (p)) < 0)
- {
- pant = p;
- p = psig (p);
- }
-
- if (p == NULL || strcmp (frase, frase (p)) != 0)
- elemento_quitado = FALSE;
- else
- {
- elemento_quitado = TRUE;
- if (pant == NULL)
- *plista = psig (p);
- else
- psig (pant) = psig (p);
- liberar_nodo_lista_tabla_hash (&p);
- }
-
- return (elemento_quitado);
- }
-
- /*
- Quita una frase de la tabla hash.
- */
-
- BOOLEAN quitar_de_tabla_hash (tabla_hash tabla, char *frase)
- {
- int valor_hash;
-
- valor_hash = clave_hash (frase);
- return (quitar_de_lista_tabla_hash (&tabla[valor_hash], frase));
- }
-
- /*
- Imprime mensaje de error de memoria insuficiente y finaliza el programa.
- */
-
- void error_de_memoria (void)
- {
- printf ("\nERROR: Memoria insuficiente.\n");
- getch ();
- exit (1);
- }
- ende
- end lección 8
-
- ; LECCION 9
- begin
- begine "COPIAR FICHERO UTILIZANDO FUNCIONES DE E/S DE ALTO NIVEL"
- /*
- Este programa copia un fichero a otro fichero.
- Funcionalmente este programa es similar al copy del DOS o al cat del UNIX.
- Si el fichero de salida es con, se está haciendo un type del DOS.
- Si el fichero de entrada es con, recuerda que el carácter fin de fichero
- se escribe con CTRL-Z en el DOS.
-
- La función strcpy() copia el string pasado como segundo argumento en el
- string pasado como primer argumento. La función toupper() devuelve el
- carácter pasado como argumento en mayúscula.
- */
-
- #include <stdio.h> /* printf (), gets (), fprintf (), stderr, EOF, fopen (),
- fclose (), fgetc (), fputc (), NULL */
- #include <conio.h> /* getch () */
- #include <string.h> /* strcpy () */
- #include <ctype.h> /* toupper () */
-
- #define BOOLEAN int
- #define TRUE 1
- #define FALSE 0
-
- #define ESC 27
- #define ENTER '\r'
-
- #define NUMMAXCARACTERES 255
-
- void main (void)
- {
- BOOLEAN salir = FALSE;
- char nombre_fichero_entrada[NUMMAXCARACTERES],
- nombre_fichero_salida[NUMMAXCARACTERES];
- FILE *pfe, *pfs; /* punteros a fichero de entrada y fichero de salida resp. */
- char ch;
-
- while (! salir)
- {
- puts ("\n\nCOPIAR FICHERO CON EL SISTEMA DE FICHEROS DE ALTO NIVEL:\n");
- printf ("Introduce nombre de fichero de entrada (ENTER o CON para teclado): ");
- gets (nombre_fichero_entrada);
- if (*nombre_fichero_entrada == '\0')
- strcpy (nombre_fichero_entrada, "con");
- printf ("Introduce nombre de fichero de salida (ENTER o CON para pantalla): ");
- gets (nombre_fichero_salida);
- if (*nombre_fichero_salida == '\0')
- strcpy (nombre_fichero_salida, "con");
-
- if ((pfe = fopen (nombre_fichero_entrada, "r")) == NULL)
- fprintf (stderr, "\nERROR: No es posible abrir el fichero de entrada %s.\n",
- nombre_fichero_entrada);
- else if ((pfs = fopen (nombre_fichero_salida, "w")) == NULL)
- {
- fprintf (stderr, "\nERROR: No es posible abrir el fichero de salida %s.\n",
- nombre_fichero_salida);
- fclose (pfe);
- }
- else
- {
- int c;
- while ((c = fgetc (pfe)) != EOF)
- fputc (c, pfs);
-
- fclose (pfe);
- fclose (pfs);
- }
-
- printf ("\n\n¿Desea copiar otro fichero (S o ENTER: Sí; N o ESC: No)? ");
- do
- {
- ch = getch ();
- } while (ch != ENTER && toupper (ch) != 'S' &&
- ch != ESC && toupper (ch) != 'N');
- salir = ch == ESC || toupper (ch) == 'N';
- }
- }
- ende
- begint
- begine "COPIAR FICHERO UTILIZANDO FUNCIONES DE E/S DE BAJO NIVEL"
- /*
- Este programa copia un fichero a otro fichero.
-
- Hace lo mismo que el programa anterior con la diferencia que éste utiliza
- funciones de E/S de bajo nivel.
-
- Aunque se podría haber hecho como el programa anterior leyendo y escribiendo
- caracteres uno a uno, leer y escribir un bloque de caracteres es bastante
- más rápido.
- */
-
- #include <stdio.h> /* printf (), gets (), BUFSIZ */
- #include <conio.h> /* getch () */
- #include <string.h> /* strcpy () */
- #include <ctype.h> /* toupper () */
- #include <fcntl.h> /* O_RDONLY, O_WRONLY, O_TEXT */
- #include <io.h> /* open (), close (), read (), write () */
- #include <sys\stat.h> /* S_IREAD, S_IWRITE */
-
- #define BOOLEAN int
- #define TRUE 1
- #define FALSE 0
-
- #define ESC 27
- #define ENTER '\r'
-
- #define NUMMAXCARACTERES 255
-
- void main (void)
- {
- BOOLEAN salir = FALSE;
- char nombre_fichero_entrada[NUMMAXCARACTERES],
- nombre_fichero_salida[NUMMAXCARACTERES];
- int dfe, dfs; /* descriptores de los ficheros de entrada y de salida resp. */
- char ch;
-
- while (! salir)
- {
- puts ("\n\nCOPIAR FICHERO CON EL SISTEMA DE FICHEROS DE BAJO NIVEL:\n");
- printf ("Introduce nombre de fichero de entrada (ENTER o CON para teclado): ");
- gets (nombre_fichero_entrada);
- if (*nombre_fichero_entrada == '\0')
- strcpy (nombre_fichero_entrada, "con");
- printf ("Introduce nombre de fichero de salida (ENTER o CON para pantalla): ");
- gets (nombre_fichero_salida);
- if (*nombre_fichero_salida == '\0')
- strcpy (nombre_fichero_salida, "con");
-
- if ((dfe = open (nombre_fichero_entrada, O_RDONLY)) == -1)
- printf ("\nERROR: No es posible abrir el fichero de entrada %s.\n",
- nombre_fichero_entrada);
- else if ((dfs = open (nombre_fichero_salida,
- O_WRONLY | O_CREAT, S_IREAD | S_IWRITE)) == -1)
- /* si no se pone el último argumento, el atributo de fichero
- es sólo lectura, y no se puede borrar de disco sin cambiar
- el modo */
- {
- printf ("\nERROR: No es posible abrir el fichero de salida %s.\n",
- nombre_fichero_salida);
- close (dfe);
- }
- else
- {
- char buf[BUFSIZ];
- int n;
-
- while ((n = read (dfe, buf, BUFSIZ)) > 0)
- write (dfs, buf, n);
-
- close (dfe);
- close (dfs);
- }
-
- printf ("\n\n¿Desea copiar otro fichero (S o ENTER: Sí; N o ESC: No)? ");
- do
- {
- ch = getch ();
- } while (ch != ENTER && toupper (ch) != 'S' &&
- ch != ESC && toupper (ch) != 'N');
- salir = ch == ESC || toupper (ch) == 'N';
- }
- }
- ende
- endt
- begine " COPIAR FICH LINEA A LINEA ESCRIBIENDO NUMEROS DE LINEA "
- /*
- Copia un fichero en otro línea a línea escribiendo el número de línea al
- principio de cada línea.
-
- El fichero de entrada (de lectura) no puede tener más de NUMMAXCARACTERES
- caracteres por línea. Esto se puede solucionar leyendo carácter a carácter.
- */
-
- #include <stdio.h> /* printf (), gets (), fprintf (), stderr, EOF, fopen (),
- fclose (), fgets (), NULL */
- #include <conio.h> /* getch () */
- #include <string.h> /* strcpy () */
- #include <ctype.h> /* toupper () */
-
- #define BOOLEAN int
- #define TRUE 1
- #define FALSE 0
-
- #define ESC 27
- #define ENTER '\r'
-
- #define NUMMAXCARACTERES 255
-
- void main (void)
- {
- BOOLEAN salir = FALSE;
- char nombre_fichero_entrada[NUMMAXCARACTERES],
- nombre_fichero_salida[NUMMAXCARACTERES];
- FILE *pfe, *pfs; /* punteros a fichero de entrada y fichero de salida resp. */
- char ch;
-
- while (! salir)
- {
- puts ("\n\nCOPIAR FICHERO LINEA A LINEA:\n");
- printf ("Introduce nombre de fichero de entrada (ENTER o CON para teclado): ");
- gets (nombre_fichero_entrada);
- if (*nombre_fichero_entrada == '\0')
- strcpy (nombre_fichero_entrada, "con");
- printf ("Introduce nombre de fichero de salida (ENTER o CON para pantalla): ");
- gets (nombre_fichero_salida);
- if (*nombre_fichero_salida == '\0')
- strcpy (nombre_fichero_salida, "con");
-
- if ((pfe = fopen (nombre_fichero_entrada, "r")) == NULL)
- fprintf (stderr, "\nERROR: No es posible abrir el fichero de entrada %s.\n",
- nombre_fichero_entrada);
- else if ((pfs = fopen (nombre_fichero_salida, "w")) == NULL)
- {
- fprintf (stderr, "\nERROR: No es posible abrir el fichero de salida %s.\n",
- nombre_fichero_salida);
- fclose (pfe);
- }
- else
- {
- int num_linea = 0;
- char linea[NUMMAXCARACTERES];
-
- while (fgets (linea, NUMMAXCARACTERES, pfe))
- fprintf (pfs, "%3d %s", ++num_linea, linea);
-
- fclose (pfe);
- fclose (pfs);
- }
-
- printf ("\n\n¿Desea copiar otro fichero (S o ENTER: Sí; N o ESC: No)? ");
- do
- {
- ch = getch ();
- } while (ch != ENTER && toupper (ch) != 'S' &&
- ch != ESC && toupper (ch) != 'N');
- salir = ch == ESC || toupper (ch) == 'N';
- }
- }
- ende
- begine " COPIAR FICHERO SELECTIVAMENTE "
- /*
- Copia las líneas de un fichero que contenga un determinado texto en
- otro fichero. Las líneas que no contengan el texto dado no son copiadas
- en el fichero de destino.
-
- El fichero de entrada (de lectura) no puede tener más de NUMMAXCARACTERES
- caracteres por línea.
-
- En ese programa aparece una función nueva cuyo prototipo está en el
- fichero string.h:
-
- char *strstr (const char *s1, const char *s2);
-
- Esta función devuelve un puntero al elemento en s1 que contiene s2
- (apunta a s2 en s1), o NULL si s2 no aparece en s1. En nuestro programa
- lo que nos interesa es que devuelve un valor distinto de cero (dirección)
- si s2 está contenido en s1 y un valor de 0 (NULL) en caso de que s2 no
- esté en s1.
- */
-
- #include <stdio.h> /* printf (), gets (), fprintf (), stderr, EOF, fopen (),
- fclose (), fgets (), fputs (), NULL */
- #include <conio.h> /* getch () */
- #include <string.h> /* strcpy (), strstr () */
- #include <ctype.h> /* toupper () */
-
- #define BOOLEAN int
- #define TRUE 1
- #define FALSE 0
-
- #define ESC 27
- #define ENTER '\r'
-
- #define NUMMAXCARACTERES 255
-
- void main (void)
- {
- BOOLEAN salir = FALSE;
- char nombre_fichero_entrada[NUMMAXCARACTERES],
- nombre_fichero_salida[NUMMAXCARACTERES];
- FILE *pfe, *pfs; /* punteros a fichero de entrada y fichero de salida resp. */
- char ch;
-
- while (! salir)
- {
- puts ("\n\nCOPIAR LINEAS SELECTIVAMENTE:\n");
- printf ("Introduce nombre de fichero de entrada (ENTER o CON para teclado): ");
- gets (nombre_fichero_entrada);
- if (*nombre_fichero_entrada == '\0')
- strcpy (nombre_fichero_entrada, "con");
- printf ("Introduce nombre de fichero de salida (ENTER o CON para pantalla): ");
- gets (nombre_fichero_salida);
- if (*nombre_fichero_salida == '\0')
- strcpy (nombre_fichero_salida, "con");
-
- if ((pfe = fopen (nombre_fichero_entrada, "r")) == NULL)
- fprintf (stderr, "\nERROR: No es posible abrir el fichero de entrada %s.\n",
- nombre_fichero_entrada);
- else if ((pfs = fopen (nombre_fichero_salida, "w")) == NULL)
- {
- fprintf (stderr, "\nERROR: No es posible abrir el fichero de salida %s.\n",
- nombre_fichero_salida);
- fclose (pfe);
- }
- else
- {
- char linea[NUMMAXCARACTERES], texto[NUMMAXCARACTERES];
-
- printf ("Introduce texto: ");
- gets (texto);
-
- while (fgets (linea, NUMMAXCARACTERES, pfe))
- if (strstr (linea, texto))
- fputs (linea, pfs);
-
- fclose (pfe);
- fclose (pfs);
- }
-
- printf ("\n\n¿Desea copiar otro fichero (S o ENTER: Sí; N o ESC: No)? ");
- do
- {
- ch = getch ();
- } while (ch != ENTER && toupper (ch) != 'S' &&
- ch != ESC && toupper (ch) != 'N');
- salir = ch == ESC || toupper (ch) == 'N';
- }
- }
- ende
- begine " COMPARAR DOS FICHEROS "
- /*
- Este programa compara dos ficheros.
- */
-
- #include <stdio.h> /* printf (), gets (), fprintf (), stderr, EOF, fopen (),
- fclose (), fgets (), fputs (), NULL */
- #include <conio.h> /* getch () */
- #include <string.h> /* strcpy (), strstr () */
- #include <ctype.h> /* toupper () */
-
- #define BOOLEAN int
- #define TRUE 1
- #define FALSE 0
-
- #define ESC 27
- #define ENTER '\r'
-
- #define NUMMAXCARACTERES 255
-
- void main (void)
- {
- BOOLEAN salir = FALSE;
- char nombre_fichero_1[NUMMAXCARACTERES],
- nombre_fichero_2[NUMMAXCARACTERES];
- FILE *pf1, *pf2; /* punteros a fichero de entrada y fichero de salida resp. */
- char ch;
-
- while (! salir)
- {
- puts ("\n\nCOMPARAR DOS FICHEROS:\n");
- printf ("Introduce nombre de primer fichero (ENTER o CON para teclado): ");
- gets (nombre_fichero_1);
- if (*nombre_fichero_1 == '\0')
- strcpy (nombre_fichero_1, "con");
- printf ("Introduce nombre de segundo fichero (ENTER o CON para teclado): ");
- gets (nombre_fichero_2);
- if (*nombre_fichero_2 == '\0')
- strcpy (nombre_fichero_2, "con");
-
- if ((pf1 = fopen (nombre_fichero_1, "r")) == NULL)
- fprintf (stderr, "\nERROR: No es posible abrir el fichero %s.\n",
- nombre_fichero_1);
- else if ((pf2 = fopen (nombre_fichero_2, "r")) == NULL)
- {
- fprintf (stderr, "\nERROR: No es posible abrir el fichero %s.\n",
- nombre_fichero_2);
- fclose (pf1);
- }
- else
- {
- int ch1, ch2;
-
- while ((ch1 = fgetc (pf1)) == (ch2 = fgetc (pf2)) && ch1 != EOF)
- ;
-
- printf ("\nLos dos ficheros comparados son %s.\n",
- feof (pf1) && feof (pf2) ? "iguales" : "distintos");
-
- fclose (pf1);
- fclose (pf2);
- }
-
- printf ("\n\n¿Desea comparar otros dos ficheros (S o ENTER: Sí; N o ESC: No)? ");
- do
- {
- ch = getch ();
- } while (ch != ENTER && toupper (ch) != 'S' &&
- ch != ESC && toupper (ch) != 'N');
- salir = ch == ESC || toupper (ch) == 'N';
- }
- }
- ende
- begine " COPIAR FICHERO CON SUSTITUCIONES "
- /*
- Copia un fichero en otro pero sustituyendo un determinado texto por otro
- nuevo texto.
-
- El fichero de entrada (de lectura) no puede tener más de NUMMAXCARACTERES
- caracteres por línea.
-
- En ese programa aparece una función nueva cuyo prototipo está en el
- fichero string.h:
-
- char *strstr (const char *s1, const char *s2);
-
- Esta función devuelve un puntero al elemento en s1 que contiene s2
- (apunta a s2 en s1), o NULL si s2 no aparece en s1. En nuestro programa
- lo que nos interesa es que devuelve un valor distinto de cero (dirección)
- si s2 está contenido en s1 y un valor de 0 (NULL) en caso de que s2 no
- esté en s1.
- */
-
- #include <stdio.h> /* printf (), gets (), fprintf (), stderr, EOF, fopen (),
- fclose (), fgets (), fputs (), NULL */
- #include <conio.h> /* getch () */
- #include <string.h> /* strcpy (), strstr () */
- #include <ctype.h> /* toupper () */
-
- #define BOOLEAN int
- #define TRUE 1
- #define FALSE 0
-
- #define ESC 27
- #define ENTER '\r'
-
- #define NUMMAXCARACTERES 255
-
- void main (void)
- {
- BOOLEAN salir = FALSE;
- char nombre_fichero_entrada[NUMMAXCARACTERES],
- nombre_fichero_salida[NUMMAXCARACTERES];
- FILE *pfe, *pfs; /* punteros a fichero de entrada y fichero de salida resp. */
- char ch;
-
- while (! salir)
- {
- puts ("\n\nCOPIAR LINEAS SELECTIVAMENTE:\n");
- printf ("Introduce nombre de fichero de entrada (ENTER o CON para teclado): ");
- gets (nombre_fichero_entrada);
- if (*nombre_fichero_entrada == '\0')
- strcpy (nombre_fichero_entrada, "con");
- printf ("Introduce nombre de fichero de salida (ENTER o CON para pantalla): ");
- gets (nombre_fichero_salida);
- if (*nombre_fichero_salida == '\0')
- strcpy (nombre_fichero_salida, "con");
-
- if ((pfe = fopen (nombre_fichero_entrada, "r")) == NULL)
- fprintf (stderr, "\nERROR: No es posible abrir el fichero de entrada %s.\n",
- nombre_fichero_entrada);
- else if ((pfs = fopen (nombre_fichero_salida, "w")) == NULL)
- {
- fprintf (stderr, "\nERROR: No es posible abrir el fichero de salida %s.\n",
- nombre_fichero_salida);
- fclose (pfe);
- }
- else
- {
- char linea[NUMMAXCARACTERES], texto_viejo[NUMMAXCARACTERES],
- texto_nuevo[NUMMAXCARACTERES], *pc1, *pc2, longitud_texto_viejo;
-
- printf ("Introduce texto viejo: ");
- gets (texto_viejo);
- printf ("Introduce texto nuevo: ");
- gets (texto_nuevo);
-
- longitud_texto_viejo = strlen (texto_viejo);
- while (fgets (linea, NUMMAXCARACTERES, pfe))
- {
- for (pc1 = linea; (pc2 = strstr (pc1, texto_viejo)) != NULL;
- pc1 = pc2 + longitud_texto_viejo)
- {
- *pc2 = 0;
- fprintf (pfs, "%s%s", pc1, texto_nuevo);
- }
- fputs (pc1, pfs);
- }
-
- fclose (pfe);
- fclose (pfs);
- }
-
- printf ("\n\n¿Desea copiar otro fichero (S o ENTER: Sí; N o ESC: No)? ");
- do
- {
- ch = getch ();
- } while (ch != ENTER && toupper (ch) != 'S' &&
- ch != ESC && toupper (ch) != 'N');
- salir = ch == ESC || toupper (ch) == 'N';
- }
- }
- ende
- begine " ORDENAR FICHERO "
- /*
- Este programa lee las líneas de un fichero de entrada (que puede ser la
- consola) y escribe las líneas ordenadas en un fichero de salida (que puede
- ser la consola).
-
- La estructura del árbol y las funciones relacionadas con él están cogidas
- del segundo ejemplo de la lección 8. Ver el código fuente de aquel ejemplo
- si no se entiende algún función de árboles que en este programa.
- */
-
- #include <stdio.h> /* printf (), gets (), FILE, fopen (), fclose (), NULL,
- fprintf (), fgets () */
- #include <stdlib.h> /* exit () */
- #include <alloc.h> /* malloc (), free () */
- #include <conio.h> /* getch () */
- #include <string.h> /* strcmp (), strcpy () */
- #include <ctype.h> /* toupper () */
-
- #define BOOLEAN int
- #define TRUE 1
- #define FALSE 0
-
- #define ESC 27
- #define ENTER '\r' /* no vale '\n' */
-
- #define NUMMAXCARACTERES 255
-
- struct nodo_arbol
- {
- char linea[NUMMAXCARACTERES];
- struct nodo_arbol *pizq, *pder;
- };
-
- void inicializar_arbol (struct nodo_arbol **parb);
- void hacer_nodo_arbol (struct nodo_arbol **pa);
- void insertar_en_arbol (struct nodo_arbol **parb, char *lin);
- void imprimir_arbol (struct nodo_arbol *parb, FILE *pfichsal);
- void liberar_arbol (struct nodo_arbol **parb);
-
- void prlec9_7 (void)
- {
- BOOLEAN salir = FALSE;
- char nombre_fichero_entrada[NUMMAXCARACTERES],
- nombre_fichero_salida[NUMMAXCARACTERES],
- linea_fichero[NUMMAXCARACTERES];
- FILE *pfe, *pfs; /* punteros a fichero de entrada y fichero de salida resp. */
- char ch;
- struct nodo_arbol *parbol;
-
- while (! salir)
- {
- puts ("\n\nORDENACION DE FICHEROS.\n");
- printf ("Introduce nombre de fichero de entrada (ENTER o CON para teclado): ");
- gets (nombre_fichero_entrada);
- if (*nombre_fichero_entrada == '\0')
- strcpy (nombre_fichero_entrada, "con");
- printf ("Introduce nombre de fichero de salida (ENTER o CON para pantalla): ");
- gets (nombre_fichero_salida);
- if (*nombre_fichero_salida == '\0')
- strcpy (nombre_fichero_salida, "con");
-
- if ((pfe = fopen (nombre_fichero_entrada, "r")) == NULL)
- printf ("\nERROR: No es posible abrir el fichero de entrada %s.\n",
- nombre_fichero_entrada);
- else if ((pfs = fopen (nombre_fichero_salida, "w")) == NULL)
- {
- printf ("\nERROR: No es posible abrir el fichero de salida %s.\n",
- nombre_fichero_salida);
- fclose (pfe);
- }
- else
- {
- inicializar_arbol (&parbol);
- while (fgets (linea_fichero, sizeof (linea_fichero), pfe) != NULL)
- insertar_en_arbol (&parbol, linea_fichero);
-
- imprimir_arbol (parbol, pfs);
-
- fclose (pfe);
- fclose (pfs);
-
- liberar_arbol (&parbol);
- }
-
- printf ("\n\n¿Desea ordenar otro fichero (S o ENTER: Sí; N o ESC: No)? ");
- do
- {
- ch = getch ();
- } while (ch != ENTER && toupper (ch) != 'S' &&
- ch != ESC && toupper (ch) != 'N');
- salir = ch == ESC || toupper (ch) == 'N';
- }
- }
-
- void inicializar_arbol (struct nodo_arbol **parb)
- {
- *parb = NULL;
- }
-
- void hacer_nodo_arbol (struct nodo_arbol **pa)
- {
- if ((*pa = (struct nodo_arbol *) malloc (sizeof (struct nodo_arbol))) == NULL)
- {
- printf ("\nERROR: Memoria insuficiente.");
- exit (1);
- }
- }
-
- void insertar_en_arbol (struct nodo_arbol **parb, char *lin)
- {
- struct nodo_arbol *p, *pant, *pa;
-
- hacer_nodo_arbol (&pa);
- strcpy (pa->linea, lin);
- pa->pizq = pa->pder = NULL;
-
- p = *parb;
- pant = NULL;
- while (p != NULL)
- {
- pant = p;
- if (strcmp (p->linea, lin) > 0)
- p = p->pizq;
- else
- p = p->pder;
- }
-
- if (pant == NULL)
- *parb = pa;
- else if (strcmp (pant->linea, lin) > 0)
- pant->pizq = pa;
- else
- pant->pder = pa;
- }
-
- void imprimir_arbol (struct nodo_arbol *parb, FILE *pfichsal)
- {
- if (parb != NULL)
- {
- imprimir_arbol (parb->pizq, pfichsal);
- fprintf (pfichsal, parb->linea);
- imprimir_arbol (parb->pder, pfichsal);
- }
- }
-
- void liberar_arbol (struct nodo_arbol **parb)
- {
- if (*parb != NULL)
- {
- liberar_arbol (&(*parb)->pizq);
- liberar_arbol (&(*parb)->pder);
- free (*parb);
- }
- }
- ende
- end lección 9
-
- ; LECCION 10
- begin
- begine " CONSTANTES DEFINIDAS EN FICHERO LIMITS.H "
- /*
- Este programa imprime los valores de todas las constantes definidas en
- el fichero limits.h.
- */
-
- #include <stdio.h>
- #include <limits.h>
- #include <conio.h>
-
- void main (void)
- {
- puts ("MACROS DECLARADAS EN EL FICHERO DE CABECERA LIMITS.H:");
- printf ("\nCHAR_BIT: %d", CHAR_BIT);
- printf ("\nCHAR_MAX: %c (%d)", CHAR_MAX, CHAR_MAX);
- printf ("\nCHAR_MIN: %c (%d)", CHAR_MIN, CHAR_MIN);
- printf ("\nSCHAR_MAX: %c (%d)", SCHAR_MAX, SCHAR_MAX);
- printf ("\nSCHAR_MIN: %c (%d)", SCHAR_MIN, SCHAR_MIN);
- printf ("\nUCHAR_MAX: %c (%d)", UCHAR_MAX, UCHAR_MAX);
- printf ("\nSHRT_MAX: %hd", SHRT_MAX);
- printf ("\nSHRT_MIN: %hd", SHRT_MIN);
- printf ("\nUSHRT_MAX: %u", USHRT_MAX);
- printf ("\nINT_MAX: %d", INT_MAX);
- printf ("\nINT_MIN: %d", INT_MIN);
- printf ("\nUINT_MAX: %u", UINT_MAX);
- printf ("\nLONG_MAX: %ld", LONG_MAX);
- printf ("\nLONG_MIN: %ld", LONG_MIN);
- printf ("\nULONG_MAX: %lu", ULONG_MAX);
- getch ();
- }
- ende
- begine " MACROS Y FUNCIONES DECLARADAS EN FICHERO CTYPE.H "
- /*
- Este programa muestra la utilización y funcionamiento de todas las
- macros y funciones que se encuentran declaradas en el fichero ctype.h.
-
- Recordar que las teclas especiales como las teclas de función generan
- dos caracteres: carácter 0 y carácter de exploración.
-
- Si este programa se compila en un compilador de Turbo C las tres líneas
- entre las directivas #ifdef-#endif serán compiladas, si se compila en
- cualquier otro compilador de C, estas tres líneas no serán compiladas.
- */
-
- #include <ctype.h> /* macros y funciones de caracteres */
- #include <stdio.h> /* printf (), puts () */
- #include <conio.h> /* getch (), getche () */
-
- void main (void)
- {
- char ch;
-
- puts ("PROGRAMA PARA PROBAR MACROS Y FUNCIONES DE CTYPE.H");
-
- do
- {
- printf ("\n\nPulsa una tecla (ESC para salir): ");
- ch = getche ();
- printf ("\n");
- printf ("\nisalnum(%c) devuelve %d.", ch, isalnum(ch));
- printf ("\nisalpha(%c) devuelve %d.", ch, isalpha(ch));
- printf ("\nisdigit(%c) devuelve %d.", ch, isdigit(ch));
- printf ("\niscntrl(%c) devuelve %d.", ch, iscntrl(ch));
- printf ("\nisascii(%c) devuelve %d.", ch, isascii(ch));
- printf ("\nisprint(%c) devuelve %d.", ch, isprint(ch));
- printf ("\nisgraph(%c) devuelve %d.", ch, isgraph(ch));
- printf ("\nislower(%c) devuelve %d.", ch, islower(ch));
- printf ("\nisupper(%c) devuelve %d.", ch, isupper(ch));
- printf ("\nispunct(%c) devuelve %d.", ch, ispunct(ch));
- printf ("\nisspace(%c) devuelve %d.", ch, isspace(ch));
- printf ("\nisxdigit(%c) devuelve %d.", ch, isxdigit(ch));
- #ifdef __TURBOC__
- printf ("\n_toupper(%c) devuelve %c.", ch, _toupper(ch));
- printf ("\n_tolower(%c) devuelve %c.", ch, _tolower(ch));
- printf ("\ntoascii(%c) devuelve %c.", ch, toascii(ch));
- #endif
- printf ("\ntoupper(%c) devuelve %c.", ch, toupper(ch));
- printf ("\ntolower(%c) devuelve %c.", ch, tolower(ch));
- } while (ch != 27); /* mientras ch sea distinto de escape */
-
- printf ("\n\nPulsa cualquier tecla para finalizar. ");
- getch ();
- }
- ende
- begine " COMPRESION/DESCOMPRESION DE FICHEROS "
- /*
-
- Este programa comprime y descomprime ficheros utilizando el algoritmo
- de Fuffman.
-
-
- INTRODUCCION TEORICA:
-
- Considera el problema siguiente. Supongamos que tenemos un alfabeto de n
- símbolos y un mensaje muy largo consistente de los símbolos de ese alfa-
- beto. Nosotros queremos codificar este mensaje como una hilera muy larga
- de bits (definimos un bit como 0 ó 1) asignando un código de hileras de
- bit a cada símbolo del alfabeto y concatenando los códigos individuales
- de los símbolos que hacen el mensaje, para producir una forma codificada
- del mensaje. Por ejemplo, supongamos que el alfabeto consiste de los cua-
- tro símbolos A, B, C, D y los códigos asignados a estos símbolos es como
- sigue:
- -------------------------
- Símbolo Código
- A 010
- B 100
- C 000
- D 111
- -------------------------
-
- El mensaje ABACCDA sería codificado como 010100010000000111010. Sin em-
- bargo esta codificación sería ineficiente puesto que se utilizan 3 bits
- para cada número, entonces se requerirían 21 bits para codificar el men-
- saje en forma total. Supongamos que se utiliza un código de 2 bit para
- cada símbolo en la forma que sigue:
-
- -------------------------
- Símbolo Código
- A 10
- B 01
- C 10
- D 11
- -------------------------
-
- En este caso el código para el mensaje sería 00010010101100, el cual re-
- quiere únicamente 14 bits. Deseamos encontrar un código que minimiza la
- longitud del mensaje total codificado.
-
- Reexaminemos el ejemplo anterior. Cada una de las letras B y D aparecen
- sólo una vez en el mensaje, mientras que la letra A aparece tres veces.
- Es decir, que si se escoge un código en el cual a la letra A se le asigna
- la hilera de bits más corta comparado con las letras B y D, la longitud
- del mensaje codificado será menor. Esto se debe a que el código más corto
- (que representa la letra A) aparece más frecuentemente que el código más
- largo. En realidad podríamos asignar los siguientes códigos:
-
- -------------------------
- Símbolo Código
- A 0
- B 110
- C 10
- D 111
- -------------------------
-
- Utilizando este código, el mensaje ABACCDA quedaría codificado como 01100
- 10101110, el cual requiere únicamente 13 bits. En mensajes muy largos que
- contienen símbolos que aparecen muy rara vez, habría un ahorro muy sustan-
- cial. Observa que el código para un símbolo no debe ser un prefijo del có-
- digo para otro. Esto es cierto si la decodificación se hace de izquierda a
- derecha. Si el código para un símbolo x, c(x), fuera el prefijo del código
- para un símbolo y, c(y), entonces cuando se encuentre c(x), no estaría muy
- claro si c(x) representa al símbolo x o si es la primera parte de c(y). En
- nuestro ejemplo la hilera de bits es recorrida de izquierda a derecha. Si
- se encuentra un 0 como el primer bit, se tendría como símbolo la letra A;
- en caso contrario se tendría B, C o D y se analizaría el bit siguiente. Si
- el segundo bit es un 0, entonces tenemos el símbolo C; de lo contrario debe
- ser B o D y se analizaría el tercer bit. Si el tercer bit es un 0, el sím-
- bolo es una B; si es 1, el símbolo es una D. Tan pronto como se ha encon-
- trado el primer símbolo, el proceso se repite partiendo nuevamente con el
- bit siguiente para encontrar el segundo símbolo.
-
- Lo anterior sugiere que se debe encontrar un método de codificación en for-
- ma óptima de acuerdo a la frecuencia de ocurrencia de cada símbolo en el
- mensaje. Primero encontrar los dos símbolos que aparecen menos frecuente-
- mente. En nuestro ejemplo estos son B y D. El último bit de sus códigos
- muestra la diferencia entre ellos: 0 para el caso de B, y 1 para el caso
- de D. Combina estos dos símbolos en un solo símbolo BD, cuyo código repre-
- sente qué símbolo es, ya sea B o D. La frecuencia de ocurrencia de este
- nuevo símbolo es la suma de las frecuencias de sus dos símbolos constitu-
- yentes. Es decir, la frecuencia de BD, es 2. En este caso tendríamos ahora
- tres símbolos: A (con frecuencia 3), C (con frecuencia 2), y BD (con fre-
- cuencia 2). De nuevo escoje los dos símbolos con menor frecuencia: C y BD.
- El último bit de sus códigos los diferencia entre sí: 0 para C y 1 para BD.
- Los dos símbolos son ahora combinados en un solo símbolo CBD con frecuencia
- 4. Ahora tendremos dos símbolos únicamente: A y CBD. Estos son combinados
- en un solo símbolo ACBD. El último bit de los códigos para A y CBD muestra
- la diferencia entre ellos: 0 para A y 1 para CBD.
-
- El símbolo ACBD contiene ahora el alfabeto en forma completa; a éste se le
- asigna la hilera de bits nulo de longitud 0 como código. Esto significa que
- al comienzo de la decodificación antes de que cualquier bit haya sido exa-
- minado, estamos seguros que cualquier símbolo está contenido en ACBD. Los
- dos símbolos que contienen ACBD (A y CBD) se le asignan los códigos 0 y 1,
- respectivamente. Si se encuentra un 0, el símbolo codificado es una A; si
- se encuentra 1, es C, B o D. Igualmente los símbolos que constituyen CBD
- (C y BD) se le asignan los códigos 10 y 11, respectivamente. El primer bit
- indica que el símbolo es uno de los constituyentes de CBD y el segundo bit
- indica que es C o BD. El símbolo que compone BD (B y D) se le asigna los
- códigos 110 y 111. Mediante este proceso, los símbolos que aparecen frecuen-
- temente en el mensaje quedan con los códigos más cortos que los símbolos que
- aparecen con menos frecuencia.
-
- La acción de combinar dos símbolos en uno solo sugiere el uso de un árbol
- binario. Cada nodo sin hojas del árbol representa un símbolo y las hojas re-
- presentan el símbolo del alfabeto original. La siguiente figura muestra el
- árbol binario construido utilizando el ejemplo anterior. Cada nodo en la
- ilustración contiene un símbolo y su frecuencia.
-
- ACBD.7
- / \
- A.3 CBD.4
- / \
- C.2 BD.2
- / \
- B.1 D.1
-
- La figura que viene a continuación demuestra el árbol binario construido
- por este método para el alfabeto de la tabla de frecuencias adjunta.
-
- IHFBDEGCA.91
- / \
- / \
- IHFBD.38 EGCA.53
- / \ / \
- / \ / \
- I.15 HFBD.23 E.25 GCA.28
- / \ / \
- / \ / \
- HFB.11 D.12 GC.13 A.15
- / \ / \
- / \ / \
- HF.5 B.6 G.6 C.7
- / \
- / \
- H.1 F.4
-
- Símbolo Frecuencia Código │ Símbolo Frecuencia Código │ Símbolo Frecuencia Código
- ───────────────────────────┼───────────────────────────┼───────────────────────────
- A 15 111 │ D 12 011 │ G 6 1100
- B 6 0101 │ E 25 10 │ H 1 01000
- C 7 1101 │ F 4 01001 │ I 15 00
-
- Estos árboles son denominados árboles de Huffman debido al descubridor de
- este método de codificación.
-
- Una vez que el árbol de Huffman se ha construido, el código de cualquier
- símbolo en el alfabeto se puede determinar empezando con la hoja que re-
- presenta el símbolo y subiendo hasta la raíz. El código es inicializado
- en cero. Cada vez que se asciende en una ramificación de la izquierda se
- agrega un 0 a la izquierda en el código; y cada vez que se asciende en
- un brazo a la derecha se coloca un 1 a la izquierda del código.
-
- Observa que al construir el árbol y al obtener los códigos, es necesario
- únicamente el de guardar los enlaces entre cada nodo con su padre y una
- indicación con respecto a si el nodo es un hijo izquierdo o derecho; los
- enlaces del padre con cualquiera de sus dos hijos no es necesario. Cada
- nodo contiene tres campos: padre, tipo de hijo, y frecuencia. El campo
- padre es un puntero al nodo padre. Si el nodo es la raíz, su campo de
- padre será nulo. El valor del campo tipo de hijo es una de las constantes
- hijo izquierdo o hijo derecho dependiendo de si el nodo es un hijo iz-
- quierdo o derecho. El campo frecuencia es la frecuencia de ocurrencia del
- símbolo representado por ese nodo.
-
-
- CODIFICACION:
-
- El algoritmo seguido en el programa ha sido el algoritmo de Huffman. Las
- estructuras utilizadas son las siguientes:
- 1)
- enum tipo_hijo { hijo_izq, hijo_der };
-
- struct nodo_arbol_asc
- {
- enum tipo_hijo tipo_hijo;
- struct nodo_arbol_asc *ppadre;
- };
-
- typedef struct nodo_arbol_asc *punt_arbol_asc;
-
- Este árbol es el que se utiliza en el proceso de compresión y se trata
- de un árbol ascendente.
-
- 2)
- struct nodo_arbol_desc
- {
- uchar caracter;
- struct nodo_arbol_desc *phijoizq, *phijoder;
- };
-
- typedef struct nodo_arbol_desc *punt_arbol_desc;
-
- Este árbol es el que se utiliza en el proceso de descompresión y se
- trata de un árbol descendente, es decir, para acceder a cualquier
- nodo de él, sólo necesitamos un puntero a la cabeza del árbol.
-
- 3)
- struct nodo_lista_frecuencias
- {
- uchar caracter;
- ulong frecuencia;
- union
- {
- punt_arbol_asc puntarbolasc;
- punt_arbol_desc puntarboldesc;
- } puntarbol;
- struct nodo_lista_frecuencias *psiguiente;
- };
-
- typedef struct nodo_lista_frecuencias *punt_lista_frecuencias;
-
- Se trata de una lista ordenada por frecuencias necesaria en el proceso
- de compresión para ir insertando en el árbol primero los caracteres que
- aparecen menos veces quedando así los caracteres que aparecen con más
- frecuencia en un nivel superior a los que aparecen con menos frecuencia,
- de este modo, a los que aparecen menos veces les corresponde un número
- menor de bits que a los que parecen más.
-
- 4)
- typedef struct tabla
- {
- ulong frecuencia;
- punt_arbol_asc parbolasc;
- } tabla_de_caracteres [256];
-
- Tabla en la que cada entrada corresponde a uno de los 256 caracteres
- que componen el código ASCII.
-
- 5)
- struct nodo_pila
- {
- uchar bit;
- struct nodo_pila *psig;
- };
-
- typedef struct nodo_pila *punt_pila;
-
- Pila necesaria en varios procesos de compresión y descompresión.
-
- El proceso seguido en este programa para implantar este algoritmo es el
- siguiente:
-
- - Compresión:
-
- Al leer los caracteres actualizo en tabchar la frecuencia de cada uno de
- ellos. Una vez leídos todos los caracteres, creo la lista de frecuencias
- ordenada de menor a mayor frecuencia. Mientras esta lista no esté vacía,
- cojo el primer elemento de la lista, si el puntero al árbol de este nodo
- es NULO es que se trata de un nuevo elemento del árbol por lo que inser-
- to el nuevo nodo en el árbol y guardo en la entrada correspondiente de
- tabchar un puntero al nodo del árbol, si por el contrario el puntero al
- árbol de ese nodo no es NULO, es que se trata de un nodo existente ya en
- el árbol; a continuación leo el siguiente nodo de la lista de frecuen-
- cias y hago lo mismo que he hecho con el primer nodo. Ahora mismo ya
- tengo dos nodos (dos punteros al árbol) que he de unir en el árbol a un
- sólo nodo, este nuevo nodo creado en el árbol lo inserto en el lugar
- correspondiente en la lista de frecuencias. De nuevo vuelvo a leer dos
- nodos de la lista de frecuencias y así sucesivamente. Repitiendo esta
- operación hasta que quede un sólo nodo en la lista de frecuencias se
- crea el árbol. Una vez creado el árbol, el resto es muy simple.
-
- - Descompresión:
-
- El árbol se crea casi igual que en la compresión, la única diferencia es
- que las frecuencias de tabchar se cargan de la cabecera del fichero, y
- que a la hora de unir dos nodos del árbol, en la compresión se hace que
- los nodos hijos apunten al nodo padre y en la descompresión se hace que
- el nodo padre apunte a los nodos hijos. Por lo demás el proceso de crea-
- ción del árbol es igual que en la compresión como se puede ver en las
- implementaciones en C. Una vez creado el árbol, la decodificación es
- bastante fácil.
-
-
- ESTADISTICAS
-
- Para comprobar el ahorro de espacio que produce este programa se han obte-
- nido los siguientes datos al comprimir los siguientes programas:
-
- bytes del fichero número de carácteres diferentes bytes del fichero comprimido
- origen del fichero origen (includo la cabecera)
- ----------------- ------------------------------- ----------------------------
- 104 41 192 (185%)
- 206 3 41 (20%)
- 1.196 84 862 (72%)
- 4.375 83 2.835 (65%)
- 14.733 253 13.279 (90%)
- 16.004 19 6.333 (40%)
- 16.882 83 9.976 (59%)
- 17.790 89 11.243 (63%)
- 30.392 256 26.866 (88%)
- 31.557 84 19.272 (61%)
- 40.195 93 26.843 (67%)
- 290.249 256 256.961 (88%)
- Media Media Media
- 85.348 133 72.524 (85%)
-
-
- OBSERVACIONES FINALES:
-
- 1) Habréis observado en el programa que los ficheros son binarios y no de
- texto. Esto ha de ser así forzosamente ya que los ficheros a manejar
- pueden tener caracteres fin de fichero (código ASCII 26) en su contenido.
-
- 2) Para que se pueda ejecutar el programa desde el tutor se ha modificado
- un poco la función main para que el programa, en vez de aceptar los
- argumentos desde la línea de órdenes del sistema operativo, los lea
- con funciones de entrada estándar. Si se va a conviertir este ejemplo
- en un programa ejecutable, recomendaría utilizar la función main() que
- está entre comentarios y no la que se encuentra activa en este momento,
- en dicho caso la función mensaje_terminar() no sirve para nada y reco-
- miendo quitarla. Al compilar tened en cuenta que hay comentarios anidados
- en la función main() y puede haber compiladores que no permitan tal cosa.
-
- */
-
- /* Ficheros de cabecera: */
-
- #include <string.h> /* strcmp() */
- #include <ctype.h> /* tolower() */
- #include <stdlib.h> /* exit(), malloc(), free() */
- #include <stdarg.h> /* va_list, va_start(), va_end() */
- #include <stdio.h> /* FILE, fopen(), fclose(), NULL, EOF, feof(), printf(),
- putc(), getc(), fread(), fwrite(), puts(), vfprintf(), rewind() */
-
- /* Constantes y macros: */
-
- #define BOOLEAN short
- #define TRUE 1
- #define FALSE 0
-
- #define CREADOR "Antonio Lebrón Bocanegra"
- #define MARCA_DE_RECONOCIMIENTO "ALB"
-
- #define uchar unsigned char
- #define ulong unsigned long
-
- #define t(ind) (*(tabchar+(ind)))
-
- /* Estructuras y tipos: */
-
- enum tipo_hijo { hijo_izq, hijo_der };
-
- struct nodo_arbol_asc
- {
- enum tipo_hijo tipo_hijo;
- struct nodo_arbol_asc *ppadre;
- };
-
- struct nodo_arbol_desc
- {
- uchar caracter;
- struct nodo_arbol_desc *phijoizq, *phijoder;
- };
-
- typedef struct nodo_arbol_asc *punt_arbol_asc;
- typedef struct nodo_arbol_desc *punt_arbol_desc;
-
- struct nodo_lista_frecuencias
- {
- uchar caracter;
- ulong frecuencia;
- union
- {
- punt_arbol_asc puntarbolasc;
- punt_arbol_desc puntarboldesc;
- } puntarbol;
- struct nodo_lista_frecuencias *psiguiente;
- };
-
- typedef struct nodo_lista_frecuencias *punt_lista_frecuencias;
-
- typedef struct tabla
- {
- ulong frecuencia;
- punt_arbol_asc parbolasc;
- } tabla_de_caracteres [256];
-
- struct nodo_pila
- {
- uchar bit;
- struct nodo_pila *psig;
- };
-
- typedef struct nodo_pila *punt_pila;
-
- enum tipo_fichero { lectura, escritura };
-
- /* Variables globales: */
-
- BOOLEAN comprimir;
- tabla_de_caracteres tabchar;
- int nchardiferentes = 0;
- FILE *pfichero_origen, *pfichero_destino;
-
- /* Prototipos de funciones ordenadas alfabéticamente por su nombre: */
-
- FILE *abrir_fichero (char *nombre, enum tipo_fichero tipo_fich);
- void apilar_bits (punt_pila *pila, int indice);
- void apilar_nodo (punt_pila *pila, uchar bit);
- void ayuda (void);
- void leer_cabecera_cargando_tabchar (void);
- void cerrar_fichero (FILE *pfich, char *nombre_fichero);
- void crear_arbol_asc (punt_lista_frecuencias *plista);
- punt_arbol_desc crear_arbol_desc (punt_lista_frecuencias *plista);
- punt_arbol_asc crear_nodo_arbol_asc (void);
- punt_arbol_desc crear_nodo_arbol_desc (uchar ch);
- void desapilar_bits (punt_pila *pila);
- void desapilar_byte (punt_pila *pila, uchar *num_bits_significativos_de_byte, uchar *byte);
- void empezar_programa (void);
- void error_en_programa (char *lista_de_argumentos, ...);
- void escribir_cabecera (void);
- void escribir_caracteres_comprimidos (void);
- void escribir_caracteres_descomprimidos (punt_arbol_desc parbol);
- punt_lista_frecuencias inicializar_lista_frec (void);
- void inicializar_tabla_para_compresion (void);
- void inicializar_tabla_para_descompresion (void);
- void insertar_en_orden_en_lista_frec(punt_lista_frecuencias *plist, punt_lista_frecuencias pl);
- void insertar_nodo_arbol_asc_en_lista_frecuencias (punt_lista_frecuencias *plist, punt_arbol_asc parbol, ulong frecuencia);
- void insertar_nodo_arbol_desc_en_lista_frecuencias (punt_lista_frecuencias *plist, punt_arbol_desc parbol, ulong frecuencia);
- void leer_fichero_origen_cargando_tabchar (void);
- void mensaje_terminar (void);
- void proceso_compresion (void);
- void proceso_descompresion (void);
- void proceso_descomprimir (uchar *nomb_fich_origen, uchar *nomb_fich_destino);
- void proceso (char *nombre_fich_origen, char *nombre_fich_destino);
- punt_arbol_asc unir_nodos_arbol_asc (punt_arbol_asc parb[2]);
- punt_arbol_desc unir_nodos_arbol_desc (punt_arbol_desc parb[2]);
-
- /* Funciones: */
-
- /*****************************************************************************/
-
- /* FUNCION PRINCIPAL Y FUNCIONES VARIAS */
-
- /*****************************************************************************/
-
- /*
- /*
- Función principal. Analiza argumentos y si son correctos activa proceso
- principal.
- */
-
- void main (int argc, uchar *argv[])
- {
- if (argc != 4)
- ayuda ();
- else
- {
- if (tolower (*argv[1]) != 'c' && tolower (*argv[1]) != 'd')
- error_en_programa ("Error en segundo argumento.");
- comprimir = tolower (*argv[1]) == 'c';
- proceso (argv[2], argv[3]);
- }
- exit (0);
- } /* main */
- */
-
- void main (void)
- {
- #include <stdio.h> /* gets(), printf(), puts(), putch() */
- #include <conio.h> /* getch() */
-
- char ch, nombre_fichero_origen[256], nombre_fichero_destino[256];
-
- puts ("\nPROGRAMA COMPRESOR/DESCOMPRESOR DE FICHEROS.");
- printf ("\n¿Comprimir o Descomprimir (C/D)? " );
- do
- {
- ch = getch ();
- } while (tolower (ch) != 'c' && tolower (ch) != 'd');
- comprimir = tolower (putch (ch)) == 'c';
- printf ("\nIntroduce fichero origen: ");
- do
- {
- gets (nombre_fichero_origen);
- } while (!*nombre_fichero_origen);
- printf ("Introduce fichero destino: ");
- do
- {
- gets (nombre_fichero_destino);
- } while (!*nombre_fichero_destino);
- puts ("");
- proceso (nombre_fichero_origen, nombre_fichero_destino);
- mensaje_terminar ();
- exit (0);
- } /* main */
-
- void mensaje_terminar (void)
- {
- puts ("\nPulsa cualquier tecla para finalizar. ");
- getch ();
- }
-
- /*****************************************************************************/
-
- /*
- Función llamada cuando los argumentos pasados al programa son incorrectos.
- Visualiza una breve información acerca del programa.
- */
-
- void ayuda (void)
- {
- printf ("\nPrograma compresor/descompresor de ficheros por %s\n\n", CREADOR);
- puts ("Sintaxis:");
- puts (" nombre_programa [c|d] fichero_origen fichero_destino");
- } /* ayuda */
-
- /*****************************************************************************/
-
- /*
- Función llamada siempre que ocurra algún tipo de error en el programa.
- Visualiza mensaje de error y finaliza programa.
- */
-
- void error_en_programa (char *lista_de_argumentos, ...)
- {
- va_list puntero_a_los_argumentos;
-
- va_start (puntero_a_los_argumentos, lista_de_argumentos);
- vfprintf (stderr, lista_de_argumentos, puntero_a_los_argumentos);
- va_end (puntero_a_los_argumentos);
-
- mensaje_terminar ();
- exit (1);
- } /* error_en_programa */
-
- /*****************************************************************************/
-
- /*
- Abre fichero dado en modo de apertura especificado comprobando que la
- apertura se hace correctamente.
- */
-
- FILE *abrir_fichero (char *nombre, enum tipo_fichero tipo_fich)
- {
- FILE *pfi;
-
- if ((pfi = fopen (nombre, tipo_fich == escritura ? "wb" : "rb")) == NULL)
- error_en_programa ("Error al intentar abrir el fichero '%s'.", nombre);
- return (pfi);
- } /* abrir_fichero */
-
- /*****************************************************************************/
-
- /*
- Cierra fichero dado comprobando que la operación se realiza correctamente.
- */
-
- void cerrar_fichero (FILE *pfich, char *nombre_fichero)
- {
- if (fclose (pfich) == EOF)
- error_en_programa ("Error al cerrar el fichero '%s'.", nombre_fichero);
- } /* cerrar_fichero */
-
- /*****************************************************************************/
-
- /* FUNCIONES PRINCIPALES RELACIONADAS CON LOS
- PROCESOS DE COMPRIMIR Y DESCOMPRIMIR */
-
- /*****************************************************************************/
-
- /*
- Abre ficheros, llama al proceso de compresión o descompresión según
- argumentos del programa, y cierra ficheros cuando el proceso de
- compresión o descompresión ha finalizado.
- */
-
- void proceso (char *nombre_fich_origen, char *nombre_fich_destino)
- {
- pfichero_origen = abrir_fichero (nombre_fich_origen, lectura);
- pfichero_destino = abrir_fichero (nombre_fich_destino, escritura);
-
- comprimir ? proceso_compresion () : proceso_descompresion ();
-
- cerrar_fichero (pfichero_origen, nombre_fich_origen);
- cerrar_fichero (pfichero_destino, nombre_fich_destino);
- } /* proceso */
-
- /*****************************************************************************/
-
- /*
- Esta función es la que ejecuta el proceso de compresión mediante varias
- llamadas a otras funciones.
- */
-
- void proceso_compresion (void)
- {
- punt_lista_frecuencias plistafrec;
-
- puts ("Comprimiendo...");
- inicializar_tabla_para_compresion ();
- leer_fichero_origen_cargando_tabchar ();
- plistafrec = inicializar_lista_frec ();
- crear_arbol_asc (&plistafrec);
- escribir_caracteres_comprimidos ();
- }
-
- /*****************************************************************************/
-
- /*
- Esta función es la que ejecuta el proceso de descompresión mediante varias
- llamadas a otras funciones. El proceso seguido es similar al proceso de
- compresión.
- */
-
- void proceso_descompresion (void)
- {
- punt_lista_frecuencias plistafrec;
- punt_arbol_desc p_cabeza_arbol;
-
- puts ("Descomprimiendo...");
- inicializar_tabla_para_descompresion ();
- leer_cabecera_cargando_tabchar ();
- plistafrec = inicializar_lista_frec ();
- p_cabeza_arbol = crear_arbol_desc (&plistafrec);
- escribir_caracteres_descomprimidos (p_cabeza_arbol);
- }
-
- /*****************************************************************************/
-
- /*
- Inicializa a 0 todos los campos de cada elemento de la tabla tabchar.
- */
-
- void inicializar_tabla_para_compresion (void)
- {
- register int i;
-
- for (i = 0; i < 256; i++)
- {
- t(i).frecuencia = 0;
- t(i).parbolasc = NULL;
- }
- } /* inicializar_tabla_para_compresion */
-
- /*****************************************************************************/
-
- /*
- Inicializa a 0 el campo de frecuencia de todos los elementos de tabchar.
- */
-
- void inicializar_tabla_para_descompresion (void)
- {
- register int i;
-
- for (i = 0; i < 256; i++)
- t(i).frecuencia = 0;
- } /* inicializar_tabla_para_descompresion */
-
- /*****************************************************************************/
-
- /*
- Esta función es llamada por proceso_compresion() para rellenar el vector
- tabchar leyendo el fichero fuente completo.
- */
-
- void leer_fichero_origen_cargando_tabchar (void)
- {
- register int ch;
-
- for (ch = getc (pfichero_origen); ! feof (pfichero_origen);
- ch = getc (pfichero_origen))
- if (t(ch).frecuencia++ == 0)
- ++nchardiferentes;
- } /* leer_caracteres */
-
- /*****************************************************************************/
-
- /*
- Escribe caracteres comprimidos en fichero destino.
-
- Algoritmo:
- ┌ principio
- │ ** byte1 es el byte que se va a escribir y byte2 representa el número
- │ ** de bits significativos de byte1
- │ ┌ mientras no fin de datos hacer
- │ │ apilar bits en ppila correspondientes al caracter leído
- │ │ ┌ mientras ppila no sea NULO hacer
- │ │ │ desapilar byte de ppila actualizando byte1 y byte2
- │ │ │ ┌ si byte = 8 entonces
- │ │ │ │ ** se ha completado byte1
- │ │ │ │ byte2 = 0
- │ │ │ │ escribir byte1 en fichero de destino
- │ │ │ └ finsi
- │ │ └ finmientras
- │ └finmientras
- │ ┌ si byte2 es distinto de cero entonces
- │ │ ┌ para ch = 1 hasta 8 - byte2 con incremento 1 hacer
- │ │ │ desplazar un bit a la izquierda byte1
- │ │ └ finpara
- │ │ escribir byte1 en fichero de destino
- │ └ finsi
- │ escribir en fichero destino 8 si byte2 = 0 o byte2 si byte2 <> 0
- └ fin
- */
-
- void escribir_caracteres_comprimidos (void)
- {
- punt_pila ppila = NULL;
- struct { uchar byte1, byte2; } byte;
- int ch; /* byte1 es el byte propiamente dicho y byte2 es el número de bits
- significativos de byte1 */
-
- rewind (pfichero_origen);
- byte.byte1 = byte.byte2 = 0;
- escribir_cabecera ();
- for (ch = getc (pfichero_origen); ! feof (pfichero_origen);
- ch = getc (pfichero_origen))
- {
- apilar_bits (&ppila, ch);
- while (ppila != NULL)
- {
- desapilar_byte (&ppila, &byte.byte2, &byte.byte1);
- if (byte.byte2 == 8)
- {
- byte.byte2 = 0;
- putc (byte.byte1, pfichero_destino);
- }
- }
- }
- if (byte.byte2)
- {
- byte.byte1 <<= 8 - byte.byte2;
- putc (byte.byte1, pfichero_destino);
- }
- putc (byte.byte2 ? byte.byte2 : 8, pfichero_destino);
- } /* escribir_caracteres_comprimidos */
-
- /*****************************************************************************/
-
- /*
- Escribe la cabecera en el fichero destino, la cual está compuesta de una
- marca de tres caracteres para reconocer que el fichero de origen está
- comprimido con este compresor, un carácter que representa cuántos carac-
- teres distintos hay, es decir, cuántos entradas vienen a continuación y
- finalmente tantas entradas como caracteres distintos hay constando cada
- entrada del carácter y su frecuencia.
-
- Algoritmo:
- ┌ principio
- │ escribir en fichero la marca de reconocimiento
- │ escribir en fichero el número de carácteres distintos que hay menos 1
- │ ** se le resta 1 para que quepa en un char ya que con un char sólo se
- │ ** pueden representar números desde el 0 hasta el 255 y puede haber
- │ ** 256 carácteres diferentes.
- │ ┌ para i = 0 hasta 255 con incremento 1 hacer
- │ │ ┌ si tabchar[i].frecuencia es distinto de cero entonces
- │ │ │ escribir en fichero caracter y frecuencia
- │ │ └ finsi
- │ └ finpara
- └ fin
- */
-
- void escribir_cabecera (void)
- {
- struct caracteres { uchar ch; ulong frec; } caracter;
- uchar nchardif = nchardiferentes - 1; /* para que quepa en un uchar (0-255) */
- register int i;
- char *marca_de_reconoc = MARCA_DE_RECONOCIMIENTO;
-
- fwrite (marca_de_reconoc, strlen (MARCA_DE_RECONOCIMIENTO), 1,
- pfichero_destino);
- putc (nchardif, pfichero_destino);
- for (i = 0; i < 256; i++)
- if (t(i).frecuencia)
- {
- caracter.ch = i;
- caracter.frec = t(i).frecuencia;
- fwrite (&caracter, sizeof (struct caracteres), 1, pfichero_destino);
- }
- } /* escribir_cabecera */
-
- /*****************************************************************************/
-
- /*
- Esta función es llamada por proceso_descompresion() para rellenar el vector
- tabchar leyendo la cabecera del fichero destino. Al mismo tiempo comprueba
- que el fichero a descomprimir es un fichero comprimido previamente con este
- compresor.
- */
-
- void leer_cabecera_cargando_tabchar (void)
- {
- struct caracteres { uchar ch; ulong frec; } caracter;
- int nchardif;
- register int i;
- char *marca_de_reconoc = MARCA_DE_RECONOCIMIENTO;
-
- fread (marca_de_reconoc, strlen (MARCA_DE_RECONOCIMIENTO), 1,
- pfichero_origen);
- if (strcmp (marca_de_reconoc, MARCA_DE_RECONOCIMIENTO))
- error_en_programa ("No es un programa comprimido con este compresor.");
- nchardif = getc (pfichero_origen) + 1;
- for (i = 1 ; i <= nchardif ; i++)
- {
- fread (&caracter, sizeof (struct caracteres), 1, pfichero_origen);
- t(caracter.ch).frecuencia = caracter.frec;
- }
- } /* leer_cabecera_cargando_tabchar */
-
- /*****************************************************************************/
-
- /*
- Escribe caracteres descomprimidos en fichero destino.
-
- Algoritmo:
- ┌ principio
- │ leer ch, ch1 y ch2 del fichero origen
- │ ** lee tres caracteres para cuando ch2 = EOF, entonces el valor de
- │ ** ch1 representará los bits significativos de ch
- │ parbolaux = parbol
- │ salir = FALSO
- │ nbits = 0
- │ ┌ mientras salir = FALSO entonces
- │ │ ┌ mientras (nbits < 8 si ch2 <> EOF ó nbits < ch1 si ch2 = EOF)
- │ │ │ y parbolaux->phijoizq <> NULO y parbolaux->phijoder <> NULO))
- │ │ │ ┌ si primer bit de ch es 1 entonces
- │ │ │ │ parbolaux = parbolaux->phijoder
- │ │ │ │ sino
- │ │ │ │ parbolaux = parbolaux->phijoizq
- │ │ │ └ finsi
- │ │ │ nbits = bbits + 1
- │ │ │ ch = ch desplazado un bit a la izquierda
- │ │ └ finmientras
- │ │ ┌ si parbolaux->phijoizq = NULO y parbolaux->phijoder = NULO
- │ │ │ escribir parbolaux->caracter en fichero de destino
- │ │ │ parbolaux = parbol
- │ │ └ finsi
- │ │ ┌ si nbits = 8 en caso ch2 <> EOF o nbits = ch1 en caso ch2 = EOF
- │ │ │ nbits = 0
- │ │ │ ┌ si ch2 = EOF entonces
- │ │ │ │ salir = VERDAD
- │ │ │ │ sino
- │ │ │ │ ch = ch1
- │ │ │ │ ch1 = ch2
- │ │ │ │ ch2 = obtener carácter de fichero origen
- │ │ │ └ finsi
- │ │ └ finsi
- │ └ finmientras
- └ fin
- */
-
- void escribir_caracteres_descomprimidos (punt_arbol_desc parbol)
- {
- int ch, ch1, ch2, nbits = 0;
- BOOLEAN salir = FALSE, ff;
- punt_arbol_desc parbolaux = parbol;
-
- ch = getc (pfichero_origen);
- if (feof (pfichero_origen))
- error_en_programa ("El fichero comprimido no es correcto.");
- ch1 = getc (pfichero_origen);
- if (feof (pfichero_origen))
- error_en_programa ("El fichero comprimido no es correcto.");
- ch2 = getc (pfichero_origen);
- ff = feof (pfichero_origen);
- while (! salir)
- {
- while (nbits < (ff ? ch1 : 8) && parbolaux->phijoizq != NULL)
- {
- parbolaux = ch & 0x80 ? parbolaux->phijoder : parbolaux->phijoizq;
- ++nbits;
- ch <<= 1;
- }
- if (parbolaux->phijoizq == NULL)
- {
- putc (parbolaux->caracter, pfichero_destino);
- parbolaux = parbol;
- }
- if (nbits == (ff ? ch1 : 8))
- {
- nbits = 0;
- if (ff)
- salir = TRUE;
- else
- {
- ch = ch1;
- ch1 = ch2;
- ch2 = getc (pfichero_origen);
- ff = feof (pfichero_origen);
- }
- }
- }
- } /* escribir_caracteres_descomprimidos */
-
- /*****************************************************************************/
-
- /* FUNCIONES RELACIONADAS CON EL ARBOL ASCENDENTE */
-
- /*****************************************************************************/
-
- void crear_arbol_asc (punt_lista_frecuencias *plista)
- {
- register short i;
- punt_arbol_asc parb[2];
- punt_lista_frecuencias plistaaux;
- ulong suma_frecuencias;
-
- while (*plista != NULL && (*plista)->psiguiente != NULL)
- {
- suma_frecuencias = 0;
- for (i = 0 ; i <= 1; i++)
- {
- if ((*plista)->puntarbol.puntarbolasc == NULL)
- t((*plista)->caracter).parbolasc = parb[i] = crear_nodo_arbol_asc ();
- else
- parb[i] = (*plista)->puntarbol.puntarbolasc;
- suma_frecuencias += (*plista)->frecuencia;
- plistaaux = *plista;
- *plista = (*plista)->psiguiente;
- free (plistaaux);
- }
- insertar_nodo_arbol_asc_en_lista_frecuencias (plista,
- unir_nodos_arbol_asc (parb), suma_frecuencias);
- }
- free (*plista);
- } /* crear_abol_asc */
-
- /*****************************************************************************/
-
- punt_arbol_asc crear_nodo_arbol_asc (void)
- {
- punt_arbol_asc parbolaux = (punt_arbol_asc) malloc
- (sizeof (struct nodo_arbol_asc));
- if ( parbolaux == NULL )
- error_en_programa ("No hay suficiente memoria.");
- return (parbolaux);
- } /* crear_nodo_arbol_asc */
-
- /*****************************************************************************/
-
- punt_arbol_asc unir_nodos_arbol_asc (punt_arbol_asc parb[2])
- {
- punt_arbol_asc parbolaux = (punt_arbol_asc) malloc
- (sizeof (struct nodo_arbol_asc));
- if (parbolaux == NULL)
- error_en_programa ("No hay suficiente memoria.");
- (*parb)->tipo_hijo = hijo_izq;
- (*(parb + 1))->tipo_hijo = hijo_der;
- parbolaux->ppadre = NULL;
- (*parb)->ppadre = (*(parb + 1))->ppadre = parbolaux;
- return (parbolaux);
- } /* unir_nodos_arbol_asc */
-
- /*****************************************************************************/
-
- void insertar_nodo_arbol_asc_en_lista_frecuencias
- (punt_lista_frecuencias *plist, punt_arbol_asc parbol, ulong frecuencia)
- {
- punt_lista_frecuencias plistaaux = (punt_lista_frecuencias) malloc
- (sizeof (struct nodo_lista_frecuencias));
-
- if (plistaaux == NULL)
- error_en_programa ("No hay suficiente memoria.");
- else
- {
- plistaaux->frecuencia = frecuencia;
- plistaaux->puntarbol.puntarbolasc = parbol;
- plistaaux->psiguiente = NULL;
- insertar_en_orden_en_lista_frec (plist, plistaaux);
- }
- } /* insertar_nodo_arbol_asc_en_lista_frecuencias */
-
- /*****************************************************************************/
-
- /* FUNCIONES RELACIONADAS CON EL ARBOL DESCENDENTE */
-
- /*****************************************************************************/
-
- punt_arbol_desc crear_arbol_desc (punt_lista_frecuencias *plista)
- {
- register short i;
- punt_arbol_desc parb[2], p_arbol_nodo_raiz;
- punt_lista_frecuencias plistaaux;
- ulong suma_frecuencias;
-
- while (*plista != NULL && (*plista)->psiguiente != NULL)
- {
- suma_frecuencias = 0;
- for (i = 0 ; i <= 1; i++)
- {
- if ((*plista)->puntarbol.puntarboldesc == NULL)
- parb[i] = crear_nodo_arbol_desc ((*plista)->caracter);
- else
- parb[i] = (*plista)->puntarbol.puntarboldesc;
- suma_frecuencias += (*plista)->frecuencia;
- plistaaux = *plista;
- *plista = (*plista)->psiguiente;
- free (plistaaux);
- }
- insertar_nodo_arbol_desc_en_lista_frecuencias (plista,
- unir_nodos_arbol_desc (parb), suma_frecuencias);
- }
- p_arbol_nodo_raiz = (*plista)->puntarbol.puntarboldesc;
- free (*plista);
- return (p_arbol_nodo_raiz);
- } /* crear_abol_desc */
-
- /*****************************************************************************/
-
- punt_arbol_desc crear_nodo_arbol_desc (uchar ch)
- {
- punt_arbol_desc parbolaux = (punt_arbol_desc) malloc
- (sizeof (struct nodo_arbol_desc));
- if (parbolaux == NULL)
- error_en_programa ("No hay suficiente memoria.");
- parbolaux->caracter = ch;
- parbolaux->phijoizq = parbolaux->phijoder = NULL;
- return (parbolaux);
- } /* crear_nodo_arbol_desc */
-
- /*****************************************************************************/
-
- punt_arbol_desc unir_nodos_arbol_desc (punt_arbol_desc parb[2])
- {
- punt_arbol_desc parbolaux = (punt_arbol_desc) malloc
- (sizeof (struct nodo_arbol_desc));
-
- if (parbolaux == NULL)
- error_en_programa ("No hay suficiente memoria.");
- parbolaux->phijoizq = *parb;
- parbolaux->phijoder = *(parb + 1);
- return (parbolaux);
- } /* unir_nodos_arbol_asc */
-
- /*****************************************************************************/
-
- void insertar_nodo_arbol_desc_en_lista_frecuencias
- (punt_lista_frecuencias *plist, punt_arbol_desc parbol, ulong frecuencia)
- {
- punt_lista_frecuencias plistaaux = (punt_lista_frecuencias) malloc
- (sizeof (struct nodo_lista_frecuencias));
-
- if (plistaaux == NULL)
- error_en_programa ("No hay suficiente memoria.");
- else
- {
- plistaaux->frecuencia = frecuencia;
- plistaaux->puntarbol.puntarboldesc = parbol;
- plistaaux->psiguiente = NULL;
- insertar_en_orden_en_lista_frec (plist, plistaaux);
- }
- } /* insertar_nodo_arbol_desc_en_lista_frecuencias */
-
- /*****************************************************************************/
-
- /* FUNCIONES RELACIONADAS CON EL MANEJO DE LAS LISTAS */
-
- /*****************************************************************************/
-
- punt_lista_frecuencias inicializar_lista_frec (void)
- {
- register int i;
- punt_lista_frecuencias plista = NULL, plistaaux;
-
- for (i = 0; i < 256; i++)
- if (t(i).frecuencia)
- {
- plistaaux = (punt_lista_frecuencias) malloc (sizeof (struct
- nodo_lista_frecuencias));
- if (plistaaux == NULL)
- error_en_programa ("No hay suficiente memoria.");
- plistaaux->caracter = i;
- plistaaux->frecuencia = t(i).frecuencia;
- if (comprimir)
- plistaaux->puntarbol.puntarbolasc = NULL;
- else
- plistaaux->puntarbol.puntarboldesc = NULL;
- plistaaux->psiguiente = NULL;
- insertar_en_orden_en_lista_frec (&plista, plistaaux);
- }
- return (plista);
- } /* incializar_lista_frec */
-
- /*****************************************************************************/
-
- void insertar_en_orden_en_lista_frec (punt_lista_frecuencias *plist,
- punt_lista_frecuencias pl)
- {
- if (*plist == NULL)
- *plist = pl;
- else
- {
- punt_lista_frecuencias plaux;
- uchar caractertemp;
- ulong frecuenciatemp;
- punt_arbol_asc parbolasctemp;
- punt_arbol_desc parboldesctemp;
-
- plaux = *plist;
- while (plaux->frecuencia <= pl->frecuencia && plaux->psiguiente != NULL)
- plaux = plaux->psiguiente;
- if (plaux->psiguiente == NULL)
- plaux->psiguiente = pl;
- else
- { /* insertar pl delante de plaux en *plist */
- if (plaux == *plist)
- {
- pl->psiguiente = *plist;
- *plist = pl;
- }
- else
- {
- pl->psiguiente = plaux->psiguiente;
- plaux->psiguiente = pl;
- /* intercambiar información entre pl y plaux */
- caractertemp = pl->caracter;
- pl->caracter = plaux->caracter;
- plaux->caracter = caractertemp;
- frecuenciatemp = pl->frecuencia;
- pl->frecuencia = plaux->frecuencia;
- plaux->frecuencia = frecuenciatemp;
- if (comprimir)
- {
- parbolasctemp = pl->puntarbol.puntarbolasc;
- pl->puntarbol.puntarbolasc = plaux->puntarbol.puntarbolasc;
- plaux->puntarbol.puntarbolasc = parbolasctemp;
- }
- else
- {
- parboldesctemp = pl->puntarbol.puntarboldesc;
- pl->puntarbol.puntarboldesc = plaux->puntarbol.puntarboldesc;
- plaux->puntarbol.puntarboldesc = parboldesctemp;
- }
- }
- }
- }
- } /* insertar_en_orden_en_lista_frec */
-
- /*****************************************************************************/
-
- void apilar_bits (punt_pila *pila, int indice)
- {
- punt_arbol_asc parbol = t(indice).parbolasc;
-
- while (parbol->ppadre != NULL)
- {
- apilar_nodo (pila, parbol->tipo_hijo == hijo_izq ? '0' : '1');
- parbol = parbol->ppadre;
- }
- } /* apilar_bits */
-
- /*****************************************************************************/
-
- void apilar_nodo (punt_pila *pila, uchar bit)
- {
- punt_pila ppilaaux = (punt_pila) malloc (sizeof (struct nodo_pila));
-
- if (ppilaaux == NULL)
- error_en_programa ("No hay suficiente memoria.");
- else
- ppilaaux->bit = bit;
- if (*pila == NULL)
- {
- *pila = ppilaaux;
- (*pila)->psig = NULL;
- }
- else
- {
- ppilaaux->psig = *pila;
- *pila = ppilaaux;
- }
- } /* apilar_nodo */
-
- /*****************************************************************************/
-
- void desapilar_bits (punt_pila *pila)
- {
- punt_pila pilaux;
-
- while (*pila != NULL)
- {
- pilaux = *pila;
- *pila = (*pila)->psig;
- free (pilaux);
- }
- } /* desapilar_bits */
-
- /*****************************************************************************/
-
- void desapilar_byte (punt_pila *pila, uchar *num_bits_significativos_de_byte,
- uchar *byte)
- {
- punt_pila pilaux;
-
- while (*pila != NULL && *num_bits_significativos_de_byte < 8)
- {
- pilaux = *pila;
- *pila = (*pila)->psig;
- *byte = (*byte << 1) | (pilaux->bit == '1' ? 1 : 0);
- ++*num_bits_significativos_de_byte;
- free (pilaux);
- }
- } /* desapilar_byte */
-
- /*****************************************************************************/
- ende
- begint
- begine " EJEMPLO SOBRE ALGUNAS FUNCIONES DE PANTALLA DE TURBO C "
- /*
- Programa para probar algunas funciones de la librería <conio.h>.
- El objetivo de este ejemplo no es ser útil sino ser instructivo
- e ilustrativo respecto a las funciones de consola.
- */
-
- #include <conio.h>
-
- void hacer_ventana (int x1, int y1, int x2, int y2, char *forma_caja,
- int color_texto, int color_fondo);
- void mostrar_limites_de_ventana (void);
- void mostrar_funciones_de_borrado (void);
- void mostrar_tipos_de_cursor (void);
- void mostrar_funciones_de_texto (void);
-
- void main (void)
- {
- textmode (C80);
- hacer_ventana (5, 3, 75, 22, "╔═╗║╝═╚║", BLUE, CYAN);
- mostrar_limites_de_ventana ();
- mostrar_funciones_de_borrado ();
- mostrar_tipos_de_cursor ();
- mostrar_funciones_de_texto ();
- window (1, 1, 80, 25);
- textattr (0x07);
- clrscr ();
- cputs ("Pulsa una tecla para finalizar.");
- getch ();
- }
-
- /*
- Dibuja un recuadro desde (x1,y1) hasta (x2,y2) estando la forma del
- recuadro en la cadena forma_caja: el primer carácter de esta cadena
- correspondonde al carácter de la esquina superior izquierda, el
- segundo el de la línea superior horizontal y así consecutivamente,
- siguiente las manecillas del reloj, hasta llegar al último que es el
- carácter que representa la línea vertical izquierda.
-
- La ventana de texto (window) va en realidad desde (x1+1,y1+1) hasta
- (x2-1,y2-1).
-
- Fijaos que antes de utilizar el primer gotoxy() hemos hecho un window();
- esta llamada a window() es necesaria porque las coordenadas de gotoxy()
- están referidas a la ventana de texto actual. Del mismo modo, antes de
- hacer el primer putch() tenemos que llamar a las funciones textcolor()
- y textbackground() para que a partir de entonces los caracteres se escri-
- ban con el atributo de pantalla deseado.
-
- El clrscr() se hace al final de esta función para que el fondo de la
- ventana quede pintado en pantalla con el color color_fondo.
- */
-
- void hacer_ventana (int x1, int y1, int x2, int y2, char *forma_caja,
- int color_texto, int color_fondo)
- {
- register int i;
- const char esqsupizq = *(forma_caja),
- linhorsup = *(forma_caja + 1),
- esqsupder = *(forma_caja + 2),
- linverder = *(forma_caja + 3),
- esqinfder = *(forma_caja + 4),
- linhorinf = *(forma_caja + 5),
- esqinfizq = *(forma_caja + 6),
- linverizq = *(forma_caja + 7);
-
- window (1, 1, 80, 25);
-
- textcolor (color_texto);
- textbackground (color_fondo);
-
- for (i = x1 + 1; i < x2; i++)
- {
- gotoxy (i, y1);
- putch (linhorsup);
- gotoxy (i, y2);
- putch (linhorinf);
- }
-
- for (i = y1 + 1; i < y2; i++)
- {
- gotoxy (x1, i);
- putch (linverizq);
- gotoxy (x2, i);
- putch (linverder);
- }
-
- gotoxy (x1, y1);
- putch (esqsupizq);
-
- gotoxy (x2, y1);
- putch (esqsupder);
-
- gotoxy (x1, y2);
- putch (esqinfizq);
-
- gotoxy (x2, y2);
- putch (esqinfder);
-
- window (x1 + 1, y1 + 1, x2 - 1, y2 - 1);
-
- clrscr ();
- }
-
- /*
- Esta función muestra las funciones gettextinfo() y textattr().
- */
-
- void mostrar_limites_de_ventana (void)
- {
- struct text_info ti;
-
- gettextinfo (&ti);
-
- window (1, 1, 80, 25);
- textattr (0x70);
-
- gotoxy (ti.winleft, ti.wintop);
- putch ('*');
-
- gotoxy (ti.winright, ti.wintop);
- putch ('*');
-
- gotoxy (ti.winleft, ti.winbottom);
- putch ('*');
-
- gotoxy (ti.winright, ti.winbottom);
- putch ('*');
-
- window (ti.winleft, ti.wintop, ti.winright, ti.winbottom);
- textattr (ti.attribute);
-
- gotoxy (2, 2);
- cputs (" Los cuatro * marcan los bordes de la ventana de texto definida.");
-
- getch ();
- }
-
- /*
- Muestra las funciones: delline(), insline(), clreol() y clrscr().
- */
-
- void mostrar_funciones_de_borrado (void)
- {
- cputs ("\n\n\rPulsa una tecla para borrar esta línea con delline().");
- getch ();
- delline ();
- getch ();
- insline ();
- cputs ("\n\n\rEsta línea ha sido insertada con la función insline()." );
- getch ();
- cputs ("\r");
- clreol ();
- getch ();
- cputs ("\rLínea borrada con clreol(): no desplaza líneas.");
- getch ();
- cputs ("\n\n\rPulsa una tecla para borrar pantalla.");
- getch ();
- clrscr ();
- getch ();
- }
-
- /*
- Muestra la función _setcursortype().
- */
-
- void mostrar_tipos_de_cursor (void)
- {
- _setcursortype (_NORMALCURSOR);
- cputs ("\n\rCursor normal ");
- getch ();
- _setcursortype (_SOLIDCURSOR);
- cputs ("\n\rCursor sólido ");
- getch ();
- _setcursortype (_NOCURSOR);
- cputs ("\n\rCursor invisible ");
- getch ();
- _setcursortype (_NORMALCURSOR);
- clrscr ();
- }
-
- /*
- Muestra las funciones movetext(), gettext() y puttext().
- La variable buffer para estas tres funciones se suele declarar como
- en esta función. El 80 del tamaño se refiere al número de filas, el
- 25 al número de columnas y el 2 se refiere a los dos bytes que hay
- que guardar en memoria por cada posición en la pantalla: un byte para
- el carácter y otro para el atributo de ese carácter en la pantalla.
- */
-
- void mostrar_funciones_de_texto (void)
- {
- char buffer[80*25*2];
-
- cputs ("Pulsa una tecla para mover recuadro (3,3,10,10) a (20,5)");
- getch ();
- movetext (3, 3, 10, 10, 20, 5);
- cputs ("\n\rPulsa una tecla para copiar recuadro (5,3,75,22) a memoria");
- getch ();
- gettext (5, 3, 75, 22, buffer);
- cputs ("\n\rPulsa una tecla para borrar pantalla");
- getch ();
- window (1, 1, 80, 25);
- textattr (0x70);
- clrscr ();
- cputs ("Pulsa una tecla para copiar recuadro de memoria a (6,4,76,23)");
- getch ();
- puttext (6, 4, 76, 23, buffer);
- getch ();
- }
- ende
- begine " EJEMPLO SOBRE ALGUNAS FUNCIONES GRAFICAS DE TURBO C "
- /*
- Este programa prueba la mayoría de las funciones gráficas de Turbo C.
- La única utilidad de este programa es mostrar al usuario el uso de las
- funciones gráficas.
- */
-
- #include <graphics.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <conio.h>
- #include <alloc.h>
-
- void func_arc (void);
- void func_bar (void);
- void func_bar3d (void);
- void func_circle (void);
- void func_drawpoly (void);
- void func_ellipse (void);
- void func_fillellipse (void);
- void func_fillpoly (void);
- void func_floodfill (void);
- void funcs_getaspectratio_y_setaspectratio (void);
- void func_line (void);
- void func_linerel (void);
- void func_lineto (void);
- void func_pieslice (void);
- void funcs_putimage_y_getimage (void);
- void func_putpixel (void);
- void func_rectangle (void);
- void func_restorecrtmode (void);
- void func_sector (void);
- void funcs_setfillstyle_y_setfillpattern (void);
- void func_setlinestyle (void);
- void func_settextstyle (void);
- void func_settextjustify (void);
- void fun_setusercharsize (void);
- void func_setwritemode (void);
-
- int colormax, xmax, ymax, mitx, mity, terx, tery, numfuncs, indice;
-
- struct
- {
- void (*func) (void);
- char *nomfunc;
- } funcs[] =
- {
- { func_arc, "arc" },
- { func_bar, "bar" },
- { func_bar3d, "bar3d" },
- { func_circle, "circle" },
- { func_drawpoly, "drawpoly" },
- { func_ellipse, "ellipse" },
- { func_fillellipse, "fillelipse" },
- { func_fillpoly, "fillpoly" },
- { func_floodfill, "floodfill" },
- { funcs_getaspectratio_y_setaspectratio, "getaspectratio() y función setaspectratio" },
- { func_line, "line" },
- { func_linerel, "linerel" },
- { func_lineto, "lineto" },
- { func_pieslice, "pieslice" },
- { funcs_putimage_y_getimage, "putimage() y función getimage" },
- { func_putpixel, "putpixel" },
- { func_rectangle, "rectangle" },
- { func_restorecrtmode, "rectorecrtmode" },
- { func_sector, "sector" },
- { funcs_setfillstyle_y_setfillpattern, "setfillstyle() y función setfillpattern" },
- { func_setlinestyle, "setlinestyle" },
- { func_settextstyle, "settextstyle" },
- { func_settextjustify, "settextjustify" },
- { fun_setusercharsize, "setusercharsize" },
- { func_setwritemode, "setwritemode" }
- };
-
- #define ESC 27
- #define LEFT 75
- #define RIGHT 77
- #define ENTER 13
-
- void main (void)
- {
- int driver_grafico = DETECT, modo_grafico, codigo_de_error;
- initgraph (&driver_grafico, &modo_grafico, "");
- codigo_de_error = graphresult ();
- if (codigo_de_error != grOk)
- {
- printf ("Error gráfico: %s\n", grapherrormsg (codigo_de_error));
- printf ("Presiona una tecla para finalizar");
- getch();
- }
- else
- {
- int salir = 0;
- char ch;
- char titulo[81];
- numfuncs = sizeof (funcs) / sizeof (*funcs);
- indice = 0;
- colormax = getmaxcolor ();
- xmax = getmaxx ();
- ymax = getmaxy ();
- mitx = xmax / 2;
- mity = ymax / 2;
- terx = xmax / 3;
- tery = ymax / 3;
- setcolor (colormax);
- do
- {
- cleardevice ();
- sprintf (titulo, "Función %s()", funcs[indice].nomfunc);
- outtext (titulo);
- (*funcs[indice].func) ();
- if ((ch = getch ()) == ESC)
- salir = 1;
- else
- if (ch == 0)
- if ((ch = getch ()) == LEFT)
- indice--;
- else
- if (ch == RIGHT)
- indice++;
- if (indice < 0)
- indice = numfuncs - 1;
- else
- if (indice > numfuncs - 1)
- indice = 0;
- } while (! salir);
- closegraph ();
- }
- }
-
- /*
- PODEMOS INCLUIR ESTAS DOS FUNCIONES PARA QUE SEAMOS NOSOTROS LOS QUE
- ASIGNEMOS Y DESASIGNEMOS LA MEMORIA NECESARIA PARA TRABAJAR CON GRAFICOS.
-
- NOTA: PARA COMPILAR ESTE PROGRAMA TAL Y COMO ESTA, DEBE PONER LA OPCION
- DE ANIDAR COMENTARIO A ON. SI TU VERSION DE TURBO C NO TIENE LA DIRECTIVA
- #pragma argsused, PUEDES UTILIZAR LA DIRECTIVA #pragma warn -xxx CORRES-
- PONDIENTE.
-
- /* llamada por el núcleo gráfico para asignar memoria */
- void far * far _graphgetmem (unsigned tam)
- {
- /* asigna memoria de montón far */
- return farmalloc (tam);
- }
-
- #pragma argsused /* para evitar warning de parámetro tam no usado */
- /* llamado por el núcleo gráfico para liberar memoria */
-
- void far _graphfreemem (void far *ptr, unsigned tam)
- {
- /* libera ptr de montón far */
- farfree (ptr);
- }
- */
-
- void func_arc (void)
- {
- arc (mitx, mity, 45, 90+45, tery);
- arc (mitx, mity, 180+45, -45, tery);
- }
-
- void func_bar (void)
- {
- bar (mitx-tery, mity-tery, mitx+tery, mity+tery);
- }
-
- void func_bar3d (void)
- {
- bar3d (mitx-tery, mity-tery, mitx+tery, mity+tery, ymax/5, 1);
- }
-
- void func_circle (void)
- {
- circle (mitx, mity, tery);
- }
-
- void func_drawpoly (void)
- {
- int poligono[10];
- poligono[0] = 20;
- poligono[1] = 20;
- poligono[2] = xmax - 20;
- poligono[3] = 50;
- poligono[4] = xmax - 20;
- poligono[5] = ymax - 50;
- poligono[6] = 90;
- poligono[7] = ymax - 70;
- poligono[8] = poligono[0];
- poligono[9] = poligono[1];
- drawpoly (5, poligono);
- }
-
- void func_ellipse (void)
- {
- ellipse (mitx, mity, 45, -45, terx, tery);
- }
-
- void func_fillellipse (void)
- {
- fillellipse (mitx, mity, terx, tery);
- }
-
- void func_fillpoly (void)
- {
- int poligono[10];
- poligono[0] = 20;
- poligono[1] = 20;
- poligono[2] = xmax - 20;
- poligono[3] = 50;
- poligono[4] = xmax - 20;
- poligono[5] = ymax - 50;
- poligono[6] = 90;
- poligono[7] = ymax - 70;
- poligono[8] = poligono[0];
- poligono[9] = poligono[1];
- fillpoly (5, poligono);
- }
-
- void func_floodfill (void)
- {
- rectangle (mitx, 0, xmax, ymax);
- circle (xmax - 20, mity, 20);
- circle (mitx + 20, mity, 50);
- ellipse (mitx + 100, ymax - 50, 0, 360, 150, 50);
- rectangle (mitx + 30, 30, xmax - 30, 50);
- floodfill (mitx + 1, 1, colormax);
- }
-
- void funcs_getaspectratio_y_setaspectratio (void)
- {
- int cuadx, cuady;
-
- getaspectratio (&cuadx, &cuady);
-
- circle (mitx, mity, 100); /* dibuja círculo normal */
- setaspectratio (cuadx/2, cuady);
- circle (mitx, mity, 100); /* dibuja círculo ancho */
- setaspectratio (cuadx, cuady/2); /* dibuja círculo alto */
- circle (mitx, mity, 100);
-
- setaspectratio (cuadx, cuady);
- }
-
- void func_line (void)
- {
- line (mitx, 0, mitx, ymax);
- line (0, mity, xmax, mity);
- line (0, 0, xmax, ymax);
- line (xmax, 0, 0, ymax);
- }
-
- void func_linerel (void)
- {
- moveto (0, 0);
- linerel (mitx, ymax);
- linerel (mitx, -ymax);
- linerel (0, ymax);
- linerel (-mitx, -ymax);
- linerel (-mitx, ymax);
- linerel (0, -ymax);
- }
-
- void func_lineto (void)
- {
- moveto (0, 0);
- lineto (0, ymax);
- lineto (xmax, 0);
- lineto (xmax, ymax);
- lineto (0, 0);
- }
-
- void func_pieslice (void)
- {
- pieslice (mitx, mity, 60, 180, tery);
- }
-
- #define TAMANIO_FLECHA 10
-
- void funcs_putimage_y_getimage (void)
- {
- void dibujar_flecha (int x, int y);
- void *flecha;
- int x, y;
- unsigned int tamanio;
- char ch;
-
- x = 0;
- y = mity;
-
- outtext (" [Pulsa ENTER para mover flecha]");
-
- /* dibuja la imagen para ser grabada */
- dibujar_flecha (x, y);
-
- /* calcula el tamaño de la imagen */
- tamanio = imagesize (x, y-TAMANIO_FLECHA, x+(4*TAMANIO_FLECHA), y+TAMANIO_FLECHA);
-
- /* allocate memory to hold the image */
- if ((flecha = malloc (tamanio)) == NULL)
- {
- closegraph ();
- puts ("Memoria insuficiente.");
- exit (1);
- }
-
- /* graba la imagen */
- getimage (x, y-TAMANIO_FLECHA, x+(4*TAMANIO_FLECHA), y+TAMANIO_FLECHA, flecha);
-
- /* repite hasta que es presionada una tecla distinta de ENTER */
- while ((ch = getch ()) == ENTER)
- {
- /* borra imagen vieja */
- putimage (x, y-TAMANIO_FLECHA, flecha, XOR_PUT);
-
- x += TAMANIO_FLECHA;
- if (x >= xmax)
- x = 0;
-
- /* escribe imagen nueva */
- putimage (x, y-TAMANIO_FLECHA, flecha, XOR_PUT);
- }
-
- ungetch (ch);
- free (flecha);
- }
-
- void dibujar_flecha (int x, int y)
- {
- /* dibuja una flecha en la pantalla */
- moveto (x, y);
- linerel (4*TAMANIO_FLECHA, 0);
- linerel (-2*TAMANIO_FLECHA, -1*TAMANIO_FLECHA);
- linerel (0, 2*TAMANIO_FLECHA);
- linerel (2*TAMANIO_FLECHA, -1*TAMANIO_FLECHA);
- }
-
- void func_putpixel (void)
- {
- randomize ();
- while (! kbhit())
- putpixel (random (xmax), random (ymax), random (colormax));
- }
-
- void func_rectangle (void)
- {
- int i;
- for (i = 20; i < mitx && i < mity; i += 20)
- rectangle (i, i, xmax - i, ymax - i);
- }
-
- void func_restorecrtmode (void)
- {
- char ch;
- outtextxy (0, mity, "Pulsa ENTER para ejecutar restorecrtmode()");
- if ((ch = getch ()) == ENTER)
- {
- restorecrtmode ();
- cputs ("Pulsa una tecla para volver al modo gráfico.");
- ch = getch ();
- setgraphmode (getgraphmode ());
- }
- ungetch (ch); /* por si se pulsa ESC, LEFT o RIGHT */
- }
-
- void func_sector (void)
- {
- sector (mitx, mity, 45, 180 - 45, terx, tery);
- sector (mitx, mity, 180, 360, terx, tery);
- }
-
- void funcs_setfillstyle_y_setfillpattern (void)
- {
- int numpatr = USER_FILL - EMPTY_FILL + 1;
- double gradsect = 360.0 / numpatr;
- int i;
- char patron[8] = { 0x00, 0x70, 0x20, 0x27, 0x24, 0x24, 0x07, 0x00 };
-
- for (i = EMPTY_FILL; i <= USER_FILL; i++)
- {
- if (i == USER_FILL)
- setfillpattern (patron, colormax);
- else
- setfillstyle (i, colormax);
- pieslice (mitx, mity, i * gradsect, (i + 1) * gradsect, mity - 30);
- }
-
- setfillstyle (SOLID_FILL, colormax);
- }
-
- void func_setlinestyle (void)
- {
- char *nomestlin[] =
- {
- "SOLID_LINE",
- "DOTTED_LINE",
- "CENTER_LINE",
- "DASHED_LINE",
- "USERBIT_LINE"
- };
- char *nomlinanch = "SOLID_LINE Y THICK_WIDTH";
- int estilo, patron_de_usuario, posytexto, posylinea;
-
- /* un patrón de línea definido por el usuario */
- /* en binario: "0000000000000001" */
- patron_de_usuario = 1;
-
- for (estilo = SOLID_LINE; estilo <= USERBIT_LINE; estilo++)
- {
- posytexto = textheight (nomestlin[estilo]) * (estilo + 1) * 5;
- posylinea = posytexto + textheight (nomestlin[estilo]) / 2;
- setlinestyle (estilo, patron_de_usuario, 1);
- line (0, posylinea, mitx, posylinea);
- outtextxy (mitx + 10, posytexto, nomestlin[estilo]);
- }
-
- posytexto = textheight (nomlinanch) * (estilo + 1) * 5;
- posylinea = posytexto + textheight (nomlinanch) / 2;
- setlinestyle (SOLID_LINE, 0, THICK_WIDTH);
- line (0, posylinea, mitx, posylinea);
- outtextxy (mitx + 10, posytexto, nomlinanch);
-
- setlinestyle (SOLID_LINE, 0, NORM_WIDTH);
- }
-
- void func_settextstyle (void)
- {
- char *nomest[] =
- {
- "DEFAULT",
- "TRIPLEX",
- "SMALL",
- "SANS SERIF",
- "GOTHIC"
- };
- char *nomdir[] =
- {
- "HORIZ_DIR",
- "VERT_DIR"
- };
- int tamanio, estilo, direccion;
- char msj[81];
- char ch;
-
- for (;;)
- for (tamanio = 1; tamanio <= 100; tamanio++)
- for (estilo = DEFAULT_FONT + 1; estilo <= GOTHIC_FONT; estilo++)
- for (direccion = HORIZ_DIR; direccion <= VERT_DIR; direccion++)
- {
- cleardevice ();
- graphdefaults ();
- sprintf (msj, "Función %s()", funcs[indice].nomfunc);
- outtext (msj);
- outtext (" [Pulsa ENTER para siguiente estilo]");
- settextjustify (CENTER_TEXT, CENTER_TEXT);
- settextstyle (estilo, direccion, tamanio);
- sprintf (msj, "Estilo %s, tamaño %d, dirección %s",
- nomest[estilo], tamanio, nomdir[direccion]);
- outtextxy (mitx, mity, msj);
- if ((ch = getch ()) != ENTER) /* por si se pulsa ESC, LEFT o RIGHT */
- {
- ungetch (ch);
- graphdefaults ();
- return;
- }
- }
- }
-
- void func_settextjustify (void)
- {
- char msj[80];
- char *justh[] = { "LEFT_TEXT", "CENTER_TEXT", "RIGHT_TEXT" };
- char *justv[] = { "BOTTOM_TEXT", "CENTER_TEXT", "TOP_TEXT" };
- int jh, jv;
- char ch;
-
- for (;;)
- for (jh = LEFT_TEXT; jh <= RIGHT_TEXT; jh++)
- for (jv = BOTTOM_TEXT; jv <= TOP_TEXT; jv++)
- {
- cleardevice ();
- graphdefaults ();
- sprintf (msj, "Función %s()", funcs[indice].nomfunc);
- outtext (msj);
- outtext (" [Pulsa ENTER para siguiente justificación]");
- settextjustify (jh, jv);
- sprintf (msj, "%s %s", justh[jh], justv[jv]);
- line (mitx - 4, mity, mitx + 4, mity);
- line (mitx, mity - 4, mitx, mity + 4);
- outtextxy (mitx, mity, msj);
- if ((ch = getch ()) != ENTER) /* por si se pulsa ESC, LEFT o RIGHT */
- {
- ungetch (ch);
- graphdefaults ();
- return;
- }
- }
- }
-
- void fun_setusercharsize (void)
- {
- /* selecciona un estilo de texto */
- settextstyle (TRIPLEX_FONT, HORIZ_DIR, 4);
-
- /* mueve a la posición inicial del texto */
- moveto (0, tery);
-
- /* texto normal */
- outtext ("Normal ");
-
- /* hace la anchura del texto 1/3 de la normal */
- setusercharsize (1, 3, 1, 1);
- outtext ("Corto ");
-
- /* hace la anchura del texto 3 veces la normal */
- setusercharsize (3, 1, 1, 1);
- outtext ("Ancho ");
-
- /* hace la altura del texto 1/3 de la normal */
- setusercharsize (1, 1, 1, 3);
- outtext ("Bajo ");
-
- /* hace la altura del texto 3 veces la normal */
- setusercharsize (1, 1, 3, 1);
- outtext ("Alto ");
-
- moveto (0, mity);
-
- /* hace la anchura y la altura 3 veces la normal */
- setusercharsize (3, 1, 3, 1);
- outtext ("Grande");
-
- /* hace la anchura 6 veces la normal y la altura 4 veces la normal */
- setusercharsize (6, 1, 4, 1);
- outtextxy (0, 0, "Gigante");
-
- graphdefaults ();
- }
-
- void func_setwritemode (void)
- {
- setwritemode (COPY_PUT);
- fillellipse (mitx, mity, terx, tery);
- line (0, 0, xmax, ymax);
- setwritemode (XOR_PUT);
- fillellipse (mitx, mity, terx, tery);
- line (0, ymax, xmax, 0);
- graphdefaults ();
- }
- ende
- endt
- begine " LISTADOR DE FICHEROS EN HEXADECIMAL Y EN ASCII "
- /*
- Este programa lista el contenido de un fichero, bien de texto o bien
- binario, en hexadecimal y en ASCII. Los caracteres no imprimibles se
- imprimen con un '.'.
-
- La versión del main() sin argumentos se ha suministrado para ejecutar
- este ejemplo desde el tutor. Si este ejemplo se copia en un fichero y
- se convierte en un fichero ejecutable es preferible utilizar la primera
- versión del main() (la que está ahora entre comentarios) por ser más
- práctica.
- */
-
- /*
- #include <stdio.h> /* fprintf (), stderr, fopen (), NULL, EOF, putchar () */
- #include <ctype.h> /* isprint () */
- #include <stdlib.h> /* exit () */
-
- void main (int argc, char *argv[])
- {
- FILE *fich;
- register int i;
- int buffer[16];
- unsigned long desplazamiento_en_fichero = 0;
-
- if (argc != 2)
- {
- fprintf (stderr, "\nSintaxis: nombre_programa nombre_fichero\n");
- exit (1);
- }
-
- if ((fich = fopen (argv[1], "rb")) == NULL)
- {
- fprintf (stderr, "\nNo se puede abrir el fichero %s.\n", argv[1]);
- exit (1);
- }
-
- for (; ! feof (fich); desplazamiento_en_fichero += 16)
- {
- for (i = 0; i < 16; i++)
- buffer[i] = fgetc (fich);
-
- printf ("\n%04lX:", desplazamiento_en_fichero);
-
- for (i = 0; i < 16; i++)
- buffer[i] != EOF ? printf (" %02X", buffer[i]) : printf (" ");
-
- printf (" ");
-
- for (i = 0; i < 16; i++)
- putchar (buffer[i] != EOF ? (isprint (buffer[i]) ? buffer[i] : '.') : ' ');
- }
-
- putchar ('\n');
-
- fclose (fich);
- }
- */
-
- #include <stdio.h> /* fprintf (), stderr, fopen (), NULL, EOF, putchar (),
- scanf (), puts () */
- #include <ctype.h> /* isprint () */
- #include <stdlib.h> /* exit () */
- #include <conio.h> /* getch () */
-
- void main (void)
- {
- char nombre_fich[256];
- FILE *fich;
- register int i;
- int buffer[16];
- unsigned long desplazamiento_en_fichero = 0;
-
- puts ("LISTADOR DE FICHEROS EN HEXADECIMAL Y EN ASCII.");
- printf ("\nIntroduce fichero a listar: ");
- scanf ("%s", nombre_fich);
-
- if ((fich = fopen (nombre_fich, "rb")) == NULL)
- {
- fprintf (stderr, "\nNo se puede abrir el fichero %s.\n", nombre_fich);
- getch ();
- exit (1);
- }
-
- for (; ! feof (fich); desplazamiento_en_fichero += 16)
- {
- for (i = 0; i < 16; i++)
- buffer[i] = fgetc (fich);
-
- printf ("\n%04lX:", desplazamiento_en_fichero);
-
- for (i = 0; i < 16; i++)
- buffer[i] != EOF ? printf (" %02X", buffer[i]) : printf (" ");
-
- printf (" ");
-
- for (i = 0; i < 16; i++)
- putchar (buffer[i] != EOF ? (isprint (buffer[i]) ? buffer[i] : '.') : ' ');
- }
-
- putchar ('\n');
-
- fclose (fich);
-
- getch ();
- }
- ende
- end lección 10
-
- ; LECCION 11
- begin
- begine " EJEMPLO PARA PROBAR LAS FUNCIONES DE SETJMP.H "
- /*
- Ejemplo para ver cómo funciona las funciones de setjmp.h.
- */
-
- #include <stdio.h>
- #include <setjmp.h>
- #include <stdlib.h>
- #include <conio.h>
-
- void func (jmp_buf);
-
- void main (void)
- {
- int valor;
- jmp_buf jmpb;
-
- printf ("1 ");
- valor = setjmp (jmpb);
- if (valor != 0)
- {
- printf ("3 ");
- getch ();
- exit (valor);
- }
- printf ("2 ");
- func (jmpb);
- printf ("4 ");
- }
-
- void func (jmp_buf jmpb)
- {
- longjmp (jmpb, 1);
- }
- ende
- begint
- begine " DIR "
- /*
- Lista los ficheros con una determinada máscara del directorio dado.
- */
-
- #include <stdio.h>
- #include <dir.h>
- #include <conio.h>
- #include <time.h>
-
- void main (void)
- {
- struct ffblk ffblk;
- int mas_ficheros;
- char path[MAXPATH];
-
- clrscr ();
-
- printf ("Introduce máscara de ficheros a listar: ");
- gets (path);
-
- mas_ficheros = findfirst (path, &ffblk, 0);
- while (! mas_ficheros)
- {
- printf ("\n%-13s %9ld", ffblk.ff_name, ffblk.ff_fsize);
- mas_ficheros = findnext (&ffblk);
- }
-
- putchar ('\n');
- getch ();
- }
- ende
- begine " EJEMPLO PARA PROBAR LAS FUNCIONES int86() Y bdos() "
- /*
- Programa ejemplo para probar la utilización de las funciones
- int86() y bdos().
- */
-
- #include <dos.h> /* para utilizar int86() y bdos() */
- #include <stdio.h> /* para utilizar printf() */
-
- void posicionar (int x, int y);
- void borrar_ventana (int x1, int y1, int x2, int y2);
- void borrar_pantalla (void);
- void leer_version_dos (void);
- void escribir_version_dos (void);
- char leer_caracter (void);
- void escribir_caracter (int ch);
- void leer_posicion_del_cursor (void);
- void escribir_posicion_del_cursor (void);
- void preguntar_posicion_del_cursor (void);
- void fijar_posicion_del_cursor (void);
-
- union REGS regs;
- int ch1, ch2, version_dos;
-
- void main (void)
- {
- borrar_pantalla ();
- leer_version_dos ();
- escribir_version_dos ();
- leer_posicion_del_cursor ();
- escribir_posicion_del_cursor ();
- do
- {
- preguntar_posicion_del_cursor ();
- fijar_posicion_del_cursor ();
- printf ("\n\nPulsa ESC para salir o cualquier otra tecla para continuar");
- } while (leer_caracter () != 27);
- }
-
- void posicionar (int x, int y)
- {
- regs.h.ah = 2; /* fijar posición cursor */
- regs.h.dh = y; /* fila */
- regs.h.dl = x; /* columna */
- regs.h.bh = 0; /* número de página */
- int86 (0x10, ®s, ®s);
- }
-
- void borrar_ventana (int x1, int y1, int x2, int y2)
- {
- regs.h.ah = 6; /* desplazamiento vertical ascendente (scroll up) */
- regs.h.al = 0; /* borrar ventana entera */
- regs.h.cl = x1; /* columna izquierda */
- regs.h.ch = y1; /* fila superior */
- regs.h.dl = x2; /* columna derecha */
- regs.h.dh = y2; /* fila inferior */
- regs.h.bh = 7; /* atributo de visualización para las líneas nuevas */
- int86 (0x10, ®s, ®s);
- }
-
- void borrar_pantalla (void)
- {
- borrar_ventana (0, 0, 80, 25);
- posicionar (0, 0);
- }
-
- void leer_version_dos (void)
- {
- version_dos = bdos (0x30, 0, 0);
- }
-
- void escribir_version_dos (void)
- {
- printf ("\nVersión corriente del DOS: %d.%d\n", version_dos & 0x00FF,
- (version_dos & 0xFF00) >> 8);
- }
-
- char leer_caracter (void)
- {
- regs.h.ah = 0; /* lee el siguiente carácter del teclado */
- int86 (0x16, ®s, ®s);
- return (regs.h.al);
- }
-
- void escribir_caracter (int ch)
- {
- regs.h.ah = 9; /* escribe carácter y atributo */
- regs.h.al = ch; /* carácter */
- regs.h.bh = 0; /* número de página */
- regs.h.bl = 7; /* atributo */
- regs.x.cx = 1; /* número de caracteres a repetir */
- int86 (0x10, ®s, ®s);
- }
-
- void leer_posicion_del_cursor (void)
- {
- regs.h.ah = 3; /* lee la posición del cursor */
- regs.h.bh = 0; /* número de página del display */
- int86 (0x10, ®s, ®s);
- }
-
- void escribir_posicion_del_cursor (void)
- {
- printf ("\nlínea de comienzo del cursor: %d", regs.h.ch);
- printf ("\nlínea de final de cursor: %d", regs.h.cl);
- }
-
- void preguntar_posicion_del_cursor (void)
- {
- printf ("\n\n\nIntroduzca línea de comienzo del cursor [0-7]: ");
- while ((ch1=leer_caracter()-'0') < 0 || ch1 > 7)
- ;
- escribir_caracter (ch1 + '0');
- printf ("\nIntroduzca línea de final del cursor [0-7]: ");
- while ((ch2 = leer_caracter () - '0') < 0 || ch2 > 7)
- ;
- escribir_caracter (ch2 + '0');
- }
-
- void fijar_posicion_del_cursor (void)
- {
- regs.h.ah = 1; /* ajusta el tamaño del cursor */
- regs.h.ch = ch1; /* línea de comienzo */
- regs.h.cl = ch2; /* línea de final */
- int86 (0x10, ®s, ®s);
- }
- ende
- endt
- end lección 11
-
- ; LECCION 12
- begin
- begine " ANALISIS Y EVALUACION DE EXPRESIONES "
- /*
- Este programa analiza y evalúa una expresión matemática.
-
- La expresión matemática está contenida en una cadena de caracteres y ha de
- ser una expresión matemática válida. Los espacios en blanco y tabulaciones
- son ignorados entre los elementos de la expresión. En los identificadores
- no se tiene en cuenta el caso.
-
- La expresión a evaluar puede contener las siguientes constantes:
-
- E: valor del número e
- PI: valor del número pi
-
- Las funciones permitidas en la expresión son:
-
- ** Funciones trigonométricas: ** Funciones hiperbólicas:
- sen(x), cos(x), tg(x) senh(x), cosh(x), tgh(x), cotgh(x)
- sec(x), cosec(x), cotg(x) sech(x), cosech(x), cotgh(x)
- arcsen(x), arccos(x), arctg(x) x está en radianes, si se desea
- arcsec(x), arccosec(x), arccotg(x) en grados utilizar: gradarad()
- ** Fucniones exponenciales:
- exp(x) e elevado a x cuad(x) x elevado a 2
- pot(x,y) x elevado a y pot10(x) 10 elevado a x
- ** Funciones Logarítmicas:
- ln(x) logaritmo neperiano de x
- log10(x) logaritmo decimal de x
- log(x,y) logaritmo de x en base y
- ** Funciones varias:
- abs(x) valor absoluto de x rc(x) raíz cuadrada de x
- fact(x) factorial de x gradarad(x) radianes de x grados
- sign(x) 0 si x=0, 1 si x>0, -1 si x<0
- max(x,y), min(x,y) máximo y mínimo respectivamente de x e y
- resto(x,y) resto de x / y
- hipot(x,y) hipotenusa de los catetos x e y
-
- La sintaxis de los números es:
-
- [+ | -] digitos [.digitos] [ {E | e} [+ | -] digitos ]
-
- Los operadores por orden de menor a mayor prioridad válidos en la
- expresión son:
-
- + - (binarios)
- + - (monarios)
- * / // \ (binarios)
- ^ ** (binarios)
- % ! (monarios)
-
- Consideraciones sobre la expresión:
-
- ∙ Los operadores sobre la misma línea se evaluarán de izquierda a derecha
- ∙ ^ y ** son ambos, operadores de potencia equivalentes a la función pot(x,y)
- ∙ // y \ son ambos, operadores de módulo equivalentes a la función resto(x,y)
- ∙ ! es el operador factorial equivalente a la función fact(x)
- ∙ % es el tanto por ciento
- ∙ Para cambiar las prioridades de los operadores, hacer uso de los paréntesis
-
- Examinando el programa con detalle no cuesta mucho trabajo entenderlo. No
- obstante vamos a significar que cada elemento de la expresión se denomina
- token y la variable global pt siempre apunta al principio del siguiente
- token a leer. Cada vez que se lee un token se rellena la estructura de la
- variable global tok.
-
- Aquellos usuarios que compilen este programa en un compilador distinto a
- los de Turbo C pueden tener problemas en los siguientes identificadores
- no pertenecientes al ANSI C:
-
- - Contantes M_PI y M_E definidas en math.h. La primera contiene el valor
- del número pi y la segunda contiene el valor del número e.
-
- - Función mather declarada en math.h. Esta función es un manejador de
- errores matemáticos, es decir, cada vez que ocurre un error matemático,
- el sistema la llama automáticamente.
-
- - Funciones hypot (hipotenusa) y pow10 (potencia de base 10).
-
- - Directiva #pragma warn, con la cual evitamos mensajes de warnings (avisos).
- */
-
- #include <stdio.h> /* printf(), puts() */
- #include <conio.h> /* getch () */
- #include <ctype.h> /* tolower(), isspace(), isdigit(), isalpha() */
- #include <math.h> /* funciones y tipos matemáticos */
- #include <signal.h> /* signal(), SIGFPE */
- #include <string.h> /* strchr(), stricmp() */
- #include <stdlib.h> /* strtod(), NULL, exit() */
-
- #define BOOLEAN short
- #define TRUE 1
- #define FALSE 0
-
- #define LONG_MAX_CADENA_EXPRESION 255
-
- #define esdelimitador(c) (isspace(c) || ((strchr("+-*/%^(),!\\\0",c) == NULL) ? 0 : 1))
- #define max(x,y) ((x) >= (y) ? (x) : (y))
- #define min(x,y) ((x) <= (y) ? (x) : (y))
-
- #define NUM_PARAMETROS 0xC0
- #define NUM_BITS_NUM_PAR 2
- #define NUM_MAX_PARAMETROS (1 << NUM_BITS_NUM_PAR)
- #define CODIGO_FUNCION 0x3F
-
- enum tipo_token
- {
- OPSUM, /* +, - */
- OPMUL, /* *, /, //, \ */
- OPPOT, /* ^, ** */
- OPMON, /* %, ! */
- NUMERO, /* long double */
- PARAB, /* ( */
- PARCE, /* ) */
- CONSTANTE,
- FUNCION,
- COMA, /* , */
- FIN /* \0 */
- };
-
- struct token
- {
- char token [LONG_MAX_CADENA_EXPRESION];
- enum tipo_token tipotoken;
- long double valortoken; /* en caso de que sea una constante o una variable */
- } tok; /* tiene en todo momento el token actual leído */
-
- char *tabnombreconst[] = { "E", "PI", NULL };
- long double tabvalorconst[] = { M_E, M_PI, 0 };
-
- char *tabnombrefunc[] = { "abs", "arccos", "arcsen","arctg", "cos", "sen",
- "cosh","senh", "tg", "tgh", "ln", "log10",
- "log", "exp", "cuad", "rc", "pot", "pot10",
- "max", "min", "hipot", "sign", "sec", "cosec",
- "fact","gradarad","cotg", "arcsec","arccosec",
- "arccotg", "cotgh", "sech", "cosech","resto",
- NULL };
- /* los dos primeros bits indican el número de parámetros y los seis
- siguientes, el código de la función que corresponde en principio al
- lugar que ocupan en tabnombrefunc */
- char tabvalorfunc[] = { 0x40, 0x41, 0x42, 0x43, 0x44, 0x45,
- 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B,
- 0x8C, 0x4D, 0x4E, 0x4F, 0x90, 0x51,
- 0x92, 0x93, 0x94, 0x55, 0x56, 0x57,
- 0x58, 0x59, 0x5A, 0x5B, 0x5C,
- 0x5D, 0x5E, 0x5F, 0x60, 0xA1,
- 0x00 };
-
- struct
- {
- long double tabpar [NUM_MAX_PARAMETROS];
- char numpar;
- } parametros; /* información de los parámetros de la última función leída */
-
- char *pt; /* puntero a la lista de tokens */
-
- void main (void),
- evaluar_expresion (char *lista_tokens, long double *resultado),
- buscar_identificador (void),
- error (int coderr),
- obtener_token (void),
- expresion (long double *resultad),
- termino (long double *resulta),
- factor (long double *result),
- factorpot (long double *resul),
- elemento (long double *res),
- calcular_operandos (char operador, long double *r, long double *elem),
- calcular_funcion (char codfunc, long double *r),
- factorial (long double *r);
- int matherr (struct exception *e);
- void error_overflow (int subcodigo);
-
- void main (void)
- {
- char cadena_expresion[LONG_MAX_CADENA_EXPRESION];
- long double resultado_expresion;
-
- printf ("\nIntroduce expresión: ");
- gets (cadena_expresion);
- evaluar_expresion (cadena_expresion, &resultado_expresion);
- printf ("Resultado: %Lg", resultado_expresion);
- getch ();
- }
-
- void evaluar_expresion (char *lista_tokens, long double *resultado)
- {
- signal (SIGFPE, error_overflow);
-
- pt = lista_tokens;
- *resultado = 0;
- obtener_token ();
- if (tok.tipotoken == FIN)
- error (1);
- else
- expresion (resultado);
- if (tok.tipotoken == PARCE) /* tok.tipotoken es PARCE, COMA ó FIN */
- error (3);
- else if (tok.tipotoken == COMA)
- error (12);
- }
-
- void buscar_identificador (void)
- {
- BOOLEAN encontrado = FALSE;
- register int i;
-
- for (i = 0; ! encontrado && tabnombrefunc[i] != NULL; i++)
- if (stricmp (tok.token, tabnombrefunc[i]) == 0)
- encontrado = TRUE;
- if (encontrado)
- {
- tok.tipotoken = FUNCION;
- tok.valortoken = tabvalorfunc[i-1];
- }
- else
- {
- for (i = 0; ! encontrado && tabnombreconst[i] != NULL; i++)
- if (stricmp (tok.token, tabnombreconst[i]) == 0)
- encontrado = TRUE;
- if (encontrado)
- {
- tok.tipotoken = CONSTANTE;
- tok.valortoken = tabvalorconst[i-1];
- }
- else
- error (6);
- }
- }
-
- void error (int coderr)
- {
- static char *e[] =
- {
- /* 0 */ "Error de sintaxis",
- /* 1 */ "No hay expresión",
- /* 2 */ "Carácter no válido",
- /* 3 */ "Paréntesis no emparejados",
- /* 4 */ "Nùmero no correcto (video inverso en final de número)",
- /* 5 */ "Uso incorrecto de operador",
- /* 6 */ "Identificador desconocido",
- /* 7 */ "Después del nombre de función debe ir '('",
- /* 8 */ "Función debe tener más parámetros",
- /* 9 */ "Demasiados parámetros en función",
- /* 10 */ "Función sin ')'",
- /* 11 */ "Error en el código fuente del programa",
- /* 12 */ "Carácter ',' no válido",
- /* 13 */ "Todas las funciones necesitan parámetros",
- /* 14 */ "Memoria insuficiente",
- /* 15 */ "No hay expresión entre los paréntesis",
- /* 16 */ "Error de dominio o rango en función",
- /* 17 */ "División por cero",
- /* 18 */ "Se ha producido overflow o underflow",
- /* 19 */ "Error de dominio o rango en factorial"
- };
- cprintf ("** ERROR: %s", e[coderr]);
- getch ();
- exit (1);
- }
-
- #pragma warn -par
-
- int matherr (struct exception *e)
- {
- error (16);
- return 0; /* el return nunca se ejecuta */
- }
-
- void error_overflow (int subcodigo)
- {
- error (18);
- }
-
- #pragma warn +par
-
- void obtener_token (void)
- {
- register char *temp = tok.token;
-
- while (isspace (*pt))
- pt++;
- switch (*pt++)
- {
- case 0 : tok.tipotoken = FIN;
- break;
- case '+' : tok.tipotoken = OPSUM;
- *temp = '+';
- break;
- case '-' : tok.tipotoken = OPSUM;
- *temp = '-';
- break;
- case '^' : tok.tipotoken = OPPOT;
- break;
- case '*' : if (*pt == '*')
- {
- pt++;
- tok.tipotoken = OPPOT;
- }
- else
- {
- tok.tipotoken = OPMUL;
- *temp = '*';
- }
- break;
- case '\\': tok.tipotoken = OPMUL;
- *temp = '\\';
- break;
- case '/' : tok.tipotoken = OPMUL;
- if (*pt == '/')
- {
- *temp = '\\';
- pt++;
- }
- else
- *temp = '/';
- break;
- case '!' :
- case '%' : tok.tipotoken = OPMON;
- *temp = *(pt-1);
- break;
- case '(' : tok.tipotoken = PARAB;
- break;
- case ')' : tok.tipotoken = PARCE;
- break;
- case ',' : tok.tipotoken = COMA;
- break;
- default : if (isdigit (*--pt))
- {
- tok.tipotoken = NUMERO;
- while (! esdelimitador (*pt))
- *temp++ = *pt++;
- *temp = 0;
- }
- else if (isalpha (*pt))
- {
- while (isalpha (*pt) && ! esdelimitador (*pt))
- *temp++ = *pt++;
- *temp = 0;
- if (! esdelimitador (*pt))
- error (0);
- buscar_identificador ();
- }
- else
- error (2);
- }
- }
-
- void expresion (long double *resultad)
- {
- register char op = 0;
- long double sumando;
-
- if (tok.tipotoken == OPSUM)
- {
- op = *tok.token;
- obtener_token ();
- }
- termino (resultad);
- if (op == '-')
- *resultad = -(*resultad);
- while (tok.tipotoken == OPSUM)
- {
- op = *tok.token;
- obtener_token ();
- termino (&sumando);
- calcular_operandos (op, resultad, &sumando);
- }
- }
-
- void termino (long double *resulta)
- {
- register char op;
- long double fact;
-
- factor (resulta);
- while (tok.tipotoken == OPMUL)
- {
- op = *tok.token;
- obtener_token ();
- factorpot (&fact);
- calcular_operandos (op, resulta, &fact);
- }
- }
-
- void factor (long double *result)
- {
- long double factpot;
-
- factorpot (result);
- if (tok.tipotoken == OPPOT)
- {
- obtener_token ();
- factor (&factpot);
- calcular_operandos ('^', result, &factpot);
- }
- }
-
- void factorpot (long double *resul)
- {
- elemento (resul);
- while (tok.tipotoken == OPMON)
- {
- switch (*tok.token)
- {
- case '%' : *resul /= 100; break;
- case '!' : factorial (resul); break;
- default : error (11);
- }
- obtener_token ();
- }
- if (tok.tipotoken != OPSUM && tok.tipotoken != OPMUL && tok.tipotoken != OPPOT
- && tok.tipotoken != FIN && tok.tipotoken != PARCE && tok.tipotoken != COMA)
- error (0);
- }
-
- void elemento (long double *res)
- {
- char *puntero_al_final; /* utilizado en la llamada a strtod() */
- char codfunc; /* código de una función */
- int numparfunc; /* número de parámetros de una función */
- int contparfunc; /* contador de parámetros de una función */
-
- switch (tok.tipotoken)
- {
- case PARAB :
- obtener_token ();
- if (tok.tipotoken == PARCE)
- error (15);
- expresion (res);
- if (tok.tipotoken != PARCE)
- error (3);
- break;
- case PARCE :
- error (3);
- break;
- case NUMERO :
- *res = strtod (tok.token, &puntero_al_final);
- if (*puntero_al_final != NULL)
- error (4);
- break;
- case CONSTANTE :
- *res = tok.valortoken;
- break;
- case FUNCION :
- codfunc = (char) tok.valortoken & CODIGO_FUNCION;
- numparfunc = ((char) tok.valortoken & NUM_PARAMETROS) >>
- (8 - NUM_BITS_NUM_PAR);
- obtener_token ();
- if (tok.tipotoken != PARAB)
- error (7);
- obtener_token ();
- if (tok.tipotoken == PARCE)
- error (13);
- expresion (res);
- parametros.numpar = 0;
- parametros.tabpar[parametros.numpar] = *res;
- for (contparfunc = 1; contparfunc < numparfunc; contparfunc++)
- {
- if (tok.tipotoken != COMA)
- error (8);
- obtener_token ();
- expresion (res);
- parametros.tabpar[++parametros.numpar] = *res;
- }
- if (tok.tipotoken == COMA)
- error (9);
- if (tok.tipotoken != PARCE)
- error (10);
- calcular_funcion (codfunc, res);
- break;
- case OPSUM :
- case OPMUL :
- case OPPOT :
- case OPMON :
- error (5);
- break;
- case FIN :
- error (0);
- break;
- default :
- error (11);
- }
- obtener_token ();
- if (tok.tipotoken == PARAB || tok.tipotoken == FUNCION ||
- tok.tipotoken == NUMERO || tok.tipotoken == CONSTANTE)
- error (0);
- }
-
- void calcular_operandos (char operador, long double *r, long double *elem)
- {
- switch (operador)
- {
- case '+' : *r += *elem; break;
- case '-' : *r -= *elem; break;
- case '*' : *r *= *elem; break;
- case '/' : if (!*elem) error (17); else *r /= *elem; break;
- case '\\': *r = fmod (*r, *elem); break;
- case '^' : *r = pow (*r, *elem); break;
- default : error (11);
- }
- }
-
- void calcular_funcion (char codfuncion, long double *r)
- {
- long double par1 = parametros.tabpar[0], /* parámetro 1 */
- par2 = parametros.tabpar[1]; /* parámetro 2 */
-
- switch (codfuncion)
- {
- case 0 : *r = fabs (par1); break; /* abs */
- case 1 : *r = acos (par1); break; /* arccos */
- case 2 : *r = asin (par1); break; /* arcsen */
- case 3 : *r = atan (par1); break; /* arctg */
- case 4 : *r = cos (par1); break; /* cos */
- case 5 : *r = sin (par1); break; /* sen */
- case 6 : *r = cosh (par1); break; /* cosh */
- case 7 : *r = sinh (par1); break; /* senh */
- case 8 : *r = tan (par1); break; /* tg */
- case 9 : *r = tanh (par1); break; /* tgh */
- case 10 : *r = log (par1); break; /* ln */
- case 11 : *r = log10 (par1); break; /* log10 */
- case 12 : *r = log10 (par1) / log10 (par2); break; /* log */
- case 13 : *r = exp (par1); break; /* exp */
- case 14 : *r *= *r; break; /* cuad */
- case 15 : *r = sqrt (par1); break; /* rc */
- case 16 : *r = pow (par1, par2); break; /* pot */
- case 17 : *r = pow10 (par1); break; /* pot10 */
- case 18 : *r = max (par1, par2); break; /* max */
- case 19 : *r = min (par1, par2); break; /* min */
- case 20 : *r = hypot (par1, par2); break; /* hipot */
- case 21 : *r = par1 > 0 ? 1 : par1 < 0 ? -1 : 0; break; /* sign */
- case 22 : *r = 1 / cos(par1); break; /* sec */
- case 23 : *r = 1 / sin(par1); break; /* cosec */
- case 24 : *r = par1; factorial (r);break; /* fac */
- case 25 : *r *= M_PI / 180; break; /* grad */
- case 26 : *r = 1 / tan (*r); break; /* cotg */
- case 27 : *r = acos (1 / par1); break; /* arcsec */
- case 28 : *r = asin (1 / par1); break; /* arccosec */
- case 29 : *r = atan (1 / par1); break; /* arccotg */
- case 30 : *r = 1 / tanh (par1); break; /* cotgh */
- case 31 : *r = 1 / cosh (par1); break; /* sech */
- case 32 : *r = 1 / sinh (par1); break; /* cosech */
- case 33 : *r = fmod (par1, par2); break; /* rest */
- default : error (11);
- }
- }
-
- void factorial (long double *r)
- {
- register int i;
-
- if (*r < 0 || ceil (*r) != floor (*r))
- error (19);
- else
- if (!*r)
- *r = 1;
- else
- for (i = *r - 1; i > 1; i--)
- *r *= i;
- }
- ende
- begint
- begine " LABERINTO "
- /*
- Este programa consiste en el proceso buscar la salida de un laberinto. Está
- basado en la técnica de vuelta atrás (back tracking). La vuelta atrás es una
- técnica muy útil para resolver problemas de este tipo. Puesto que se necesita
- recordar dónde se ha estado, en sentido inverso, una pila es una estructura
- de datos adecuada para la vuelta atrás.
-
- El laberinto está representado por una matriz bidimensional donde cada
- posición puede tomar cuatro valores posibles:
-
- - LIBRE: representa un camino.
- - OCUPADO: representa una pared.
- - SALIDA: salida del laberinto.
- - YA_RECORRIDO: sitio por lo que ya hemos pasado anteriormente.
-
- El laberinto y la posición inicial del laberinto se generan aleatoriamente.
-
- Proceso seguido: Lo que necesitamos simular es "ir hacia atrás al útimo
- cruce e intentar ir por otro camino". Para ello ponemos todos los posibles
- movimientos desde el cuadro que se está en la pila de bifurcaciones. Cuando
- se vaya hacia atrás, el cuadro que se saque de la pila sería el siguiente
- por el que se intentaría ir en vez de por el último cruce. Los cuadros ya
- recorridos lo almacenamos en la pila de camino para ver en pantalla la
- vuelta atrás.
-
- En resumen:
-
- 1. En el cuadro de comienzo examinamos los cuatro cuadros adyacentes (el
- de arriba, abajo y los dos laterales) y ponemos los que tengan LIBRE
- o SALIDA en la pila de bifurcaciones.
-
- 2. Marcar los cuadros que hemos visitado poniendo YA_RECORRIDO en el
- cuadro. Esto nos protegerá de los bucles infinitos.
-
- 3. Obtener de la pila el siguiente movimiento. Es decir, sacar de la
- pila de bifurcaciones. Hacer el cuadro, cuyas coordenadas hayan sido
- sacadas, el cuadro actual.
-
- 4. Repetir el proceso hasta que se alcance la salida o se intente volver
- atrás y la pila de bifurcaciones esté vacía. Cuando se intente obtener
- un camino alternativo de la pila de bifurcaciones y ésta esté vacía,
- entonces no hay más posibilidades. Esto significa que no hay salida
- desde el cuadro de comienzo. Estaríamos rodeados de unos y puntos y la
- pila de bifurcaciones está vacía.
-
- En cuanto a las funciones de pila hay que decir que una pila se representa
- como una lista lineal donde se insertan y sacan elementos del principio de
- la lista. Todas estas funciones están en el primer ejemplo de la lección
- anterior, consultarlas allí si no se entiende alguna de este programa.
- */
-
- /* Ficheros a incluir: */
-
- #include <conio.h> /* getch (), _setcursortype (), _NOCURSOR, _NORMALCURSOR,
- textcolor (), putch (), clrscr (), gotoxy (), cprintf (),
- definiciones de los colores */
- #include <stdlib.h> /* randomize (), random (), exit (), EXIT_FAILURE */
- #include <time.h> /* randomize () utiliza una función de tiempo */
- #include <alloc.h> /* malloc (), free () */
- #include <dos.h> /* delay () */
-
- /* Macros: */
-
- #define BOOLEAN short
- #define TRUE 1
- #define FALSE 0
-
- #define ESC 27
-
- #define XMAX 80
- #define YMAX 24
-
- #define escribir_linea_estado(x,y,ms) textcolor (WHITE); gotoxy (1, YMAX+1); \
- cprintf ("Posición: (%02d,%02d); Milisegundos entre movimientos (cambiar: "\
- "\x1B\x1A): %03d; ESC salir", x, y, ms);
-
- /* Tipos y variables globales: */
-
- enum tipo_posicion { LIBRE, OCUPADO, SALIDA, YA_RECORRIDO };
-
- typedef enum tipo_posicion etp;
-
- struct nodo_pila
- {
- int x, y;
- struct nodo_pila *psig;
- };
-
- typedef struct nodo_pila np;
- typedef np *pnp;
-
- int ms = 100; /* milisengundos entre movimientos */
-
- /* Prototipos de las funciones utilizadas: */
-
- void formar_laberinto_aleatorio (etp lab[YMAX+1][XMAX+1], int *px, int *py);
- void escribir_laberinto (etp lab[YMAX+1][XMAX+1], int x, int y);
- void buscar_salida (etp lab[YMAX+1][XMAX+1], int *px, int *py);
- void procesar_posiciones_adyacentes (etp lab[YMAX+1][XMAX+1], int *px, int *py,
- pnp *pbif, pnp *pcam);
- void hacer_movimiento (int x, int y, int color);
- BOOLEAN pila_vacia (pnp pil);
- void crear_nodo_pila (pnp *p);
- void inicializar_pila (pnp *pil);
- void apilar (pnp *pil, int x, int y);
- void desapilar (pnp *pil, int *px, int *py);
- void liberar_pila (pnp *pil);
-
- /* Definición de las funciones utilizadas: */
-
- /*
- Función principal.
- */
-
- void main (void)
- {
- etp laberinto[YMAX+1][XMAX+1]; /* los índices 0 no se utilizan */
- int x, y; /* contiene posiciones actuales en el recorrido */
-
- _setcursortype (_NOCURSOR);
-
- randomize ();
-
- do
- {
- formar_laberinto_aleatorio (laberinto, &x, &y);
- escribir_laberinto (laberinto, x, y);
- buscar_salida (laberinto, &x, &y);
- } while (getch () != ESC);
-
- _setcursortype (_NORMALCURSOR);
- }
-
- /*
- Rellena la matriz del laberinto con valores aleatorios.
- */
-
- void formar_laberinto_aleatorio (etp lab[YMAX+1][XMAX+1], int *px, int *py)
- {
- register int i, j;
-
- /* fila superior se rellena con OCUPADO */
- for (i = 1; i <= YMAX; i++)
- lab[i][1] = lab[i][XMAX] = OCUPADO;
-
- /* fila inferior se rellena con OCUPADO */
- for (j = 1; j <= XMAX; j++)
- lab[1][j] = lab[YMAX][j] = OCUPADO;
-
- /* elementos intermedios de la matriz se rellena con 0 (LIBRE) o 1 (OCUPADO) */
- for (i = 2; i <= YMAX-1; i++)
- for (j = 2; j <= XMAX-1; j++)
- lab[i][j] = (etp) random (2);
-
- /* se asigna SALIDA a: un elemento de la fila superior, un elemento de la
- fila inferior, un elemento de la primera columna y un elemento de la
- última columna; en ningún caso se asigna SALIDA a las esquinas ya que
- por ahí es imposible salir */
- lab[1][random(XMAX-2)+2] = lab[YMAX][random(XMAX-2)+2] =
- lab[random(YMAX-2)+2][1] = lab[random(YMAX-2)+2][XMAX] = SALIDA;
-
- /* genera posición inicial aleatoriamente con la condición de que caiga
- en un elemento de la matriz que sea LIBRE */
- do
- {
- *px = random (XMAX-2) + 2; /* genera valor aleatorio entre 2 y XMAX-1 */
- *py = random (YMAX-2) + 2; /* genera valor aleatorio entre 2 y YMAX-1 */
- } while (lab[*py][*px] != LIBRE);
- }
-
- /*
- Escribe laberinto y línea de estado en la pantalla.
- */
-
- void escribir_laberinto (etp lab[YMAX+1][XMAX+1], int x, int y)
- {
- register int i, j;
-
- clrscr ();
-
- for (i = 1; i <= YMAX; i++)
- for (j = 1; j <= XMAX; j++)
- {
- if (lab[i][j] == SALIDA)
- textcolor (YELLOW);
- else if (i == 1 || i == YMAX || j == 1 || j == XMAX)
- textcolor (LIGHTCYAN);
- else if (lab[i][j] == OCUPADO)
- textcolor (BLUE);
- else
- textcolor (YELLOW);
- gotoxy (j, i);
- putch ('█');
- }
-
- escribir_linea_estado (x, y, ms);
- }
-
- /*
- Esta función busca la salida del laberinto lab a partir de la posición
- inicial (*px,*py).
- */
-
- void buscar_salida (etp lab[YMAX+1][XMAX+1], int *px, int *py)
- {
- BOOLEAN libre, atrapado;
- pnp pila_bifurcaciones, pila_camino;
-
- inicializar_pila (&pila_bifurcaciones);
- inicializar_pila (&pila_camino);
- libre = atrapado = FALSE;
-
- hacer_movimiento (*px, *py, RED);
-
- while (! libre && ! atrapado)
- {
- lab[*py][*px] = YA_RECORRIDO;
- apilar (&pila_camino, *px, *py);
-
- procesar_posiciones_adyacentes (lab, px, py, &pila_bifurcaciones,
- &pila_camino);
-
- atrapado = pila_vacia (pila_bifurcaciones);
-
- if (! atrapado)
- {
- /* este bucle minimiza el proceso pero produce saltos en el recorrido del cursor;
- lo que hace este bucle es desechar aquellas bifurcaciones almacenadas en la
- pila que han sido ya recorridas por otras bifurcaciones posteriores */
- do
- {
- desapilar (&pila_bifurcaciones, px, py); /* puede que hayamos pasado por esa casilla después de apilarla */
- } while (lab[*py][*px] == 3 && ! pila_vacia (pila_bifurcaciones));
-
- hacer_movimiento (*px, *py, RED);
- }
-
- libre = lab[*py][*px] == SALIDA;
- }
-
- liberar_pila (&pila_bifurcaciones);
- liberar_pila (&pila_camino);
-
- gotoxy (1, YMAX+1);
- textcolor (WHITE + BLINK);
- cprintf ("%-79s", libre ? "ESTOY LIBRE" : "ESTOY ATRAPADO");
- }
-
- /*
- Dada una determinada posición (x,y), esta función apila en pila de
- bifurcaciones todas los caminos posibles a tomar a partir de esa posición.
- Si no se puede tomar ningún camino, desapila de la pila de caminos para
- volver hacia atrás.
- */
-
- void procesar_posiciones_adyacentes (etp lab[YMAX+1][XMAX+1], int *px, int *py,
- pnp *pbif, pnp *pcam)
- {
- BOOLEAN encontrada_posicion_adyacente = FALSE;
-
- while (! encontrada_posicion_adyacente)
- {
- hacer_movimiento (*px, *py, LIGHTRED); /* para deshacer el movimiento hecho al final de este bucle */
-
- if (lab[*py-1][*px] == LIBRE || lab[*py-1][*px] == SALIDA)
- {
- encontrada_posicion_adyacente = TRUE;
- apilar (pbif, *px, *py-1);
- }
-
- if (lab[*py+1][*px] == LIBRE || lab[*py+1][*px] == SALIDA)
- {
- encontrada_posicion_adyacente = TRUE;
- apilar (pbif, *px, *py+1);
- }
-
- if (lab[*py][*px-1] == LIBRE || lab[*py][*px-1] == SALIDA)
- {
- encontrada_posicion_adyacente = TRUE;
- apilar (pbif, *px-1, *py);
- }
-
- if (lab[*py][*px+1] == LIBRE || lab[*py][*px+1] == SALIDA)
- {
- encontrada_posicion_adyacente = TRUE;
- apilar (pbif, *px+1, *py);
- }
-
- if (! encontrada_posicion_adyacente)
- if (pila_vacia (*pcam))
- encontrada_posicion_adyacente = TRUE; /* salir de bucle */
- else
- {
- desapilar (pcam, px, py);
- hacer_movimiento (*px, *py, RED);
- }
- }
- }
-
- /*
- Realiza un movimiento. La realización de un movimiento consiste en compro-
- bar si se ha pulsado alguna tecla, si así es, leer la tecla para ver si es
- ESC, flecha izquierda o flecha derecha. A continuación escribe carácter con
- color indicado (RED o LIGHTRED) y por último escribe la línea de estado y
- genera un retardo.
- */
-
- void hacer_movimiento (int x, int y, int color)
- {
- /* Los caracteres especiales flecha izquierda y flecha derecha generan dos
- caracteres: flecha izquierda genera 0 y 75, y flecha derecha genera 0 y 77.
- Se ha puesto while en vez de if para el caso en que se tenga la tecla
- presionada sin soltarla (en los casos de los cursores flecha izquierda y
- flecha derecha).
- */
- while (kbhit ())
- switch (getch ())
- {
- case ESC:
- exit (0);
- case 0:
- switch (getch ())
- {
- case 75:
- if (ms > 0)
- ms--;
- break;
- case 77:
- ms++;
- break;
- }
- }
- textcolor (color);
- gotoxy (x, y);
- putch ('█');
- escribir_linea_estado (x, y, ms);
- delay (ms);
- }
-
- /*
- Devuelve TRUE si la pila está vacía.
- */
-
- BOOLEAN pila_vacia (pnp pil)
- {
- return (pil == NULL);
- }
-
- /*
- Crea un nodo de pila (se reserva memoria para él).
- */
-
- void crear_nodo_pila (pnp *p)
- {
- if ((*p = (pnp) malloc (sizeof (np))) == NULL)
- {
- gotoxy (1, YMAX+1);
- cprintf ("%-79s", "\nERROR: Memoria insuficiente.");
- exit (EXIT_FAILURE);
- }
- }
-
- /*
- Inicializa puntero a la cabeza de la pila.
- */
-
- void inicializar_pila (pnp *pil)
- {
- *pil = NULL;
- }
-
- /*
- Introduce un elemento en la pila.
- */
-
- void apilar (pnp *pil, int x, int y)
- {
- pnp p;
- crear_nodo_pila (&p);
- p->x = x;
- p->y = y;
- p->psig = *pil;
- *pil = p;
- }
-
- /*
- Saca un elemento de la pila.
- Nota: En este programa, al llamar a desapilar, podemos estar seguro de
- que la pila no está vacía.
- */
-
- void desapilar (pnp *pil, int *px, int *py)
- {
- pnp p;
- *px = (*pil)->x;
- *py = (*pil)->y;
- p = *pil;
- *pil = (*pil)->psig;
- free (p);
- }
-
- void liberar_pila (pnp *pil)
- {
- pnp p;
-
- p = *pil;
- while (p)
- {
- *pil = p->psig;
- free (p);
- p = *pil;
- }
- }
- ende
- endt
- begine " CRONOMETRAR EJECUCION DE PROCESO "
- /*
- Este programa ejecuta otro un programa cronomentrando el tiempo empleado
- en la ejecución del segundo. El programa a ejecutar puede ser un programa
- ejecutable con extensión .EXE o .COM, un fichero por lotes .BAT o un co-
- mando interno del DOS como dir. Además dicho programa se puede ejecutar
- con argumentos.
-
- El main() que está entre comentarios es la versión que toma los datos desde
- la línea de órdenes del sistema operativo en vez de preguntar por ellos con
- las funciones de entrada estándar como se hace en el main() actual.
- */
-
- #include <process.h> /* system () */
- #include <stdio.h> /* puts (), printf () */
- #include <time.h> /* time_t, difftime (), time () */
- #include <string.h> /* strcat () */
-
- /*
- void main (int argc, char **argv);
- */
-
- void main (void);
-
- void ejecutar (char *);
-
- /*
- void main (int argc, char **argv)
- {
- if (argc == 1)
- puts ("\nEste programa cronometra el tiempo empleado al ejecutar el "
- "programa\npasado como argumento.\n");
- else
- {
- int cont;
- char nombre_programa_a_ejecutar[256] = { 0 };
- for (cont = 1; cont < argc; cont++)
- {
- if (*nombre_programa_a_ejecutar)
- strcat (nombre_programa_a_ejecutar, " ");
- strcat (nombre_programa_a_ejecutar, *(argv+cont));
- }
- ejecutar (nombre_programa_a_ejecutar);
- }
- }
- */
-
- void main (void)
- {
- #include <stdio.h> /* printf (), gets () */
- #include <conio.h> /* getch () */
-
- char nombre_programa_a_ejecutar[256] = { 0 };
- printf ("\nIntroduce nombre de programa a ejecutar: ");
- do
- {
- gets (nombre_programa_a_ejecutar);
- } while (!*nombre_programa_a_ejecutar);
- ejecutar (nombre_programa_a_ejecutar);
- getch ();
- }
-
- void ejecutar (char *nombre_programa)
- {
- int valor_devuelto;
- time_t tiempo1, tiempo2;
- tiempo1 = time (NULL);
- valor_devuelto = system (nombre_programa);
- tiempo2 = time (NULL);
- if (valor_devuelto == -1)
- printf ("\nError al intentar ejecutar el programa \"%s\".",
- nombre_programa);
- else
- {
- int horas, minutos, segundos;
- unsigned segundos_totales = (unsigned) difftime (tiempo2, tiempo1);
- segundos = segundos_totales % 60;
- minutos = (segundos_totales / 60) % 60;
- horas = (segundos_totales / 3600) % 24;
- printf ("\nTiempo empleado en la ejecución del programa \"%s\":\n",
- nombre_programa);
- if (horas)
- printf ("%d hor%s ", horas, horas == 1 ? "a" : "as");
- if (horas || minutos)
- printf ("%d minut%s ", minutos, minutos == 1 ? "o" : "os");
- printf ("%d segund%s", segundos, segundos == 1 ? "o" : "os");
- }
- puts ("");
- }
- ende
- end lección 12
-